在Bash中转义字符(用于JSON)

99
我正在使用git,然后将提交消息和其他信息作为JSON负载发布到服务器。
目前我有:
MSG=`git log -n 1 --format=oneline | grep -o ' .\+'`

这会将 MSG 设置为类似以下内容的东西:

Calendar can't go back past today

那么

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

我的真实JSON还有另外几个字段。

这样做很好,但当我有类似上面的提交消息并带有撇号时,JSON会无效。

如何转义bash所需的字符?我不熟悉该语言,因此不确定从哪里开始。至少将'替换为\'应该可以解决问题。


9
额外说明,JSON 应该在值周围使用双引号(而不是单引号),因此即使它在结构上正确并且正确转义,许多(但不是全部)解析器仍然会拒绝上述内容。 - polm23
不是问题的解决方案,但其他人可能会考虑这个:http://dwaves.de/tools/escape/,在我的最小测试中似乎有效。 - Robert Lugg
14个回答

1

这是一个使用Perl进行转义的解决方案,它转义反斜杠(\)、双引号(")和控制字符U+0000U+001F

$ echo -ne "Hello, \n\tBye" | \
  perl -pe 's/(\\(\\\\)*)/$1$1/g; s/(?!\\)(["\x00-\x1f])/sprintf("\\u%04x",ord($1))/eg;'
Hello, \u000a\u0009Bye

1
我曾经也遇到过同样的问题。我试图在bash中将一个变量添加到cURL负载中,但它一直返回无效的JSON。尝试了很多转义技巧后,我找到了一个简单的方法来解决我的问题。答案就在单引号和双引号中:
 curl --location --request POST 'https://hooks.slack.com/services/test-slack-hook' \
--header 'Content-Type: application/json' \
--data-raw '{"text":'"$data"'}'

也许对某些人有用!

2
这仅适用于某些数据,而不是所有可能的值。如果您的数据包含换行符,则需要在替换为JSON之前将其更改为\n;如果数据包含双引号,则需要在它们之前加上反斜杠等。其他答案中建议使用的工具,如jqxidel,可以自动执行此操作。 - Charles Duffy

0

使用Node.js

如果你已经安装了Node.js,你可以使用node-p(打印)选项来帮助你完成这个任务:

MSG=$(MSG=$MSG node -p "JSON.stringify(process.env.MSG)")
curl -i -X POST \
  -H 'Accept: application/text' \
  -H 'Content-type: application/json' \
  -d "{'payload': {'message': $MSG}}" \
  'https://example.com'

这基本上使用了Node.js的JSON.stringify()函数来转义$MSG
(正如其他人指出的,传递给-d的值中的单引号使其成为无效的JSON,但我保留了原样。但是可以用反斜杠转义的双引号替换这些单引号。)

0

我也曾想过在提交后发送带有提交信息的消息。 一开始我尝试了和这位作者类似的方法。 但后来发现了更好、更简单的解决方案。

我只需创建一个 PHP 文件,用 wget 调用它来发送消息。 在 hooks/post-receive 中实现:

wget -qO - "http://localhost/git.php" 

in git.php:

chdir("/opt/git/project.git");
$git_log = exec("git log -n 1 --format=oneline | grep -o ' .\+'");

然后以 PHP 风格创建 JSON 并调用 CURL


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接