首页 > 解决方案 > 使字符串同时有效 JSON 和 shell 转义

问题描述

我有一个要转换为 JSON 字符串的数组。其中一个元素有一个反引号。当我尝试在 shell 中运行命令时,这会导致错误:

data = [["305", "John Smith", "Amy Smith`", "10/11/2008", "Medical", {"page_count"=>4}]]
json_str = data.to_json.gsub('"','\"')
cmd = "node myscript.js #{json_str}"
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  output = [stdout.read, stderr.read]
end 

Error retrieving data: sh: 1: Syntax error: EOF in backquote substitution

一个明显的解决方案是避开反引号:

json_str = data.to_json.gsub('"','\"').gsub('`','\\\`')

但我想转义所有可能引发 isuse 的特殊 shell 字符。Ruby 的 shellescape 对字符串进行转义,以便可以在 Bourne shell 命令行中安全地使用它。这是一个例子:

argv = "It's better to give than to receive".shellescape
argv #=> "It\\'s\\ better\\ to\\ give\\ than\\ to\\ receive"

但是看看当我将它应用于 JSON 字符串时会发生什么:

data = [["305", "John Smith", "Amy Smith`", "10/11/2008", "Medical", {"page_count"=>4}]]
data = data.to_json
 => "[[\"305\",\"John Smith\",\"Amy Smith`\",\"10/11/2008\",\"Medical\",{\"page_count\":4}]]"
data = data.to_json.shellescape

=> "\\"\\\\"\[\[\\\\\\\\"305\\\\\\\\",\\\\\\\\"约翰\史密斯\\\ \\\\\",\\\\\\\\"艾米\史密斯\`\\\\\\\\",\\\\\\\\"10/11/2008\\\\\ \\\",\\\\\\\\"医疗\\\\\\\\",\{\\\\\\\\"page_count\\\\\\\\":4\} \]\]\\\\"\\""

显然,这会引发如下错误:

SyntaxError: Unexpected token \ in JSON at position 0

发生的情况是 shellescape 也会转义空格,因为 shell 需要转义空格。但是有空格是有效且必要的 JSON。那么,如何在不破坏 JSON 的情况下转义会导致命令错误的 shell 字符呢?

标签: jsonrubylinuxbashshell

解决方案


贝壳是给人类用的,不是给机器用的。让机器生成 shell 命令是一种代码味道,表明您在错误的层进行自动化。

跳过 shell,只需使用所需的参数运行您的程序:

data = [["305", "John Smith", "Amy Smith`", "10/11/2008", "Medical", {"page_count"=>4}]]
json_str = data.to_json
Open3.popen3("node", "myscript.js", json_str) do |stdin, stdout, stderr, wait_thr|
  output = [stdout.read, stderr.read]
end 

既然没有贝壳,就没有像逃避关心的人类愚蠢。


推荐阅读