json - 使字符串同时有效 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 字符呢?
解决方案
贝壳是给人类用的,不是给机器用的。让机器生成 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
既然没有贝壳,就没有像逃避关心的人类愚蠢。
推荐阅读
- java - Java Webclient:如何序列化为 Pascal JSON?
- linux - 为什么文件不是由我指定的特定用户创建的
- arkit - 从 Xcode 加载后移动 Reality Composer 实体?
- laravel - Laravel - 在 Bootstrap 模式中登录
- javascript - 无法重新打开关闭的弹出窗口,也无法在其中添加关闭按钮的关闭代码 - Javascript
- node.js - 如何使用 2048 位的 Diffie-Hellman 创建密码?
- python - Python 只读取 CSV 文件的第一行
- c++ - 通过命名管道传递 SECURITY_ATTRIBUTES 对象
- java - 为什么 FileReader 不读取超出第一行末尾的内容?
- java - Jersey2 @BeanParam 比替代方案慢得多