使字符串都有效的JSON和外壳转义

时间:2018-12-23 18:13:28

标签: json ruby linux bash shell

我有一个要转换为JSON字符串的数组。元素之一具有反勾号。当我尝试在外壳中运行命令时,这将导致错误:

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 \\\\\\\\\”,\\\\\\\“ John \ Smith \\\\\\\\“,\\\\\\\\” Amy \ Smith \`\\\\\\\\\“,\\\\\\\”“ 2008年10月11日\\ \\\\\\“,\\\\\\\\”医疗\\\\\\\\“,\ {\\\\\\\” page_count \\\\\\\\\“: 4 \} \] \] \\\\“ \\”“

很明显,这会引发如下错误:

SyntaxError: Unexpected token \ in JSON at position 0

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

1 个答案:

答案 0 :(得分:4)

外壳是供人类使用的,而不是供机器使用的。让机器产生外壳命令是一种代码气味,表明您在错误的层进行自动化。

跳过外壳,然后使用所需的参数运行程序:

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 

由于不涉及任何外壳,因此没有人类逃避关心的愚蠢行为。