在bash中转义字符(对于JSON)

Ric*_*haw 50 bash json escaping

我正在使用git,然后将提交消息和其他位作为JSON有效负载发布到服务器.

目前我有:

MSG=`git log -n 1 --format=oneline | grep -o ' .\+'`
Run Code Online (Sandbox Code Playgroud)

它将MSG设置为:

Calendar can't go back past today
Run Code Online (Sandbox Code Playgroud)

然后

curl -i -X POST \
  -H 'Accept: application/text' \
  -H 'Content-type: application/json' \
  -d "{'payload': {'message': '$MSG'}}" \
  'https://example.com'
Run Code Online (Sandbox Code Playgroud)

我真正的JSON有另外两个领域.

这样可以正常工作,但是当我有一个提交消息(例如上面带有撇号的提交消息)时,JSON无效.

如何逃脱bash所需的角色?我不熟悉这种语言,所以不知道从哪里开始.更换'\'会做的最小,我怀疑这份工作.

pol*_*m23 56

使用Python:

这个解决方案不是纯粹的bash,但它是非侵入性的并且处理unicode.

json_escape () {
    printf '%s' "$1" | python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
}
Run Code Online (Sandbox Code Playgroud)

请注意,JSON是标准python库的一部分并且已经存在了很长时间,因此这是一个非常小的python依赖项.

或者使用PHP:

json_escape () {
    printf '%s' "$1" | php -r 'echo json_encode(file_get_contents("php://stdin"));'
}
Run Code Online (Sandbox Code Playgroud)

使用如下:

$ json_escape "???"
"\u30e4\u30db\u30fc"
Run Code Online (Sandbox Code Playgroud)

  • 我认为你需要引用`$ 1`,所以你不会丢失空格. (4认同)
  • 我喜欢这个。不难将其更改为简单的单行:`alias json_escape="python -c 'import json,sys; print json.dumps(sys.stdin.read())'"` (2认同)
  • `jq` 会做同样的事情,例如 `jq -aR <<< 'ヤホー'` (2认同)

che*_*ner 43

而不是担心如何正确引用数据,只需将其保存到文件并使用允许选项的@构造.要确保正确转义输出以用作JSON值,请使用类似生成JSON 的工具,而不是手动创建它.curl--datagitjq

jq -n --arg msg "$(git log -n 1 --format=oneline | grep -o ' .\+')" \
   '{payload: { message: $msg }}' > git-tmp.txt

curl -i -X POST \
  -H 'Accept: application/text' \
  -H 'Content-type: application/json' \
  -d @git-tmp.txt \
  'https://example.com'
Run Code Online (Sandbox Code Playgroud)

您也可以直接使用标准输入读取-d @-; 我把它作为练习让读者构建从中读取git并生成正确有效负载消息的管道curl.

(提示:这是jq ... | curl ... -d@- 'https://example.com')

  • 为什么不跳过文件并使用 `data="$(jq --arg...)"` 存储到 bash 中的变量中? (2认同)

jch*_*ook 20

jq 可以做到这一点.

轻量级,免费和用C语言编写,jqGitHub上享有超过12.5k的明星社区支持.我个人觉得它在我的日常工作流程中非常快速有用.

将字符串转换为JSON

jq -aRs . <<< '????'
Run Code Online (Sandbox Code Playgroud)

解释,

  • -a 表示"ascii输出"
  • -R 意思是"原始输入"
  • -s 表示"输出JSON文档的根"
  • . 将字符串传递给stdin(仅限bash?)

Git + Curl用例

要修复OP给出的代码示例,只需通过jq管道.

MSG=`git log -n 1 --format=oneline | grep -o ' .\+' | jq -aRs .`
Run Code Online (Sandbox Code Playgroud)

  • 对于包含换行符的文本,应添加“-s”选项,以获得单个字符串结果。 (2认同)

xsg*_*don 16

当我遇到这个问题时,我还试图在Bash中转义字符,以便使用JSON进行传输.我发现实际上有一个更大的字符列表必须被转义 - 特别是如果你试图处理自由格式文本.

我发现有两个有用的提示:

  • 使用${string//substring/replacement}此线程中描述的Bash 语法.
  • 使用tab,newline,回车等实际控制字符.在vim中,您可以输入Ctrl+,V然后输入实际的控制代码(例如Ctrl+ I用于选项卡).

我想出的最终Bash替换如下:

JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\\/\\\\} # \ 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\//\\\/} # / 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\'/\\\'} # ' (not strictly needed ?)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//\"/\\\"} # " 
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//   /\\t} # \t (tab)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//
/\\\n} # \n (newline)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^M/\\\r} # \r (carriage return)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^L/\\\f} # \f (form feed)
JSON_TOPIC_RAW=${JSON_TOPIC_RAW//^H/\\\b} # \b (backspace)
Run Code Online (Sandbox Code Playgroud)

我还没有在这个阶段找到如何正确地转义Unicode字符,这也是(显然)需要的.如果我解决这个问题,我会更新我的答案.


Ric*_*haw 11

好的,找到了该怎么做.Bash按预期原生支持,但一如既往,语法不是很容易猜到!

基本上${string//substring/replacement}返回您的图像,以便您可以使用

MSG=${MSG//\'/\\\'}
Run Code Online (Sandbox Code Playgroud)

去做这个.下一个问题是第一个正则表达式不再起作用,但可以替换为

git log -n 1 --pretty=format:'%s'
Run Code Online (Sandbox Code Playgroud)

最后,我甚至不需要逃避它们.相反,我只是把JSON中的所有'换成了'.嗯,你每天都学到一些东西.

  • 这绝不是完全符合JSON转义的.真实的东西需要用`\ t`替换标签,用`\n`替换新行,要加倍的文字反斜杠等. (4认同)

wcy*_*wcy 7

git log -n 1 --format=oneline | grep -o ' .\+' | jq --slurp --raw-input
Run Code Online (Sandbox Code Playgroud)

上一行对我有用。请参阅 https://github.com/stedolan/jq了解更多jq工具


use*_*860 5

我发现了类似的东西:

MSG=`echo $MSG | sed "s/'/\\\\\'/g"`
Run Code Online (Sandbox Code Playgroud)