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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10053678/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:16:55  来源:igfitidea点击:

Escaping characters in bash (for JSON)

jsonbashescaping

提问by Rich Bradshaw

I'm using git, then posting the commit message and other bits as a JSON payload to a server.

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

Currently I have:

目前我有:

MSG=`git log -n 1 --format=oneline | grep -o ' .\+'`

which sets MSG to something like:

它将 MSG 设置为类似:

Calendar can't go back past today

then

然后

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

My real JSON has another couple of fields.

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

This works fine, but of course when I have a commit message such as the one above with an apostrophe in it, the JSON is invalid.

这工作正常,但当然,当我有一个提交消息时,例如上面带有撇号的消息,JSON 无效。

How can I escape the characters required in bash? I'm not familiar with the language, so am not sure where to start. Replacing 'with \'would do the job at minimum I suspect.

如何转义 bash 中所需的字符?我不熟悉这门语言,所以不知道从哪里开始。替换'with\'至少可以完成我怀疑的工作。

采纳答案by Rich Bradshaw

OK, found out what to do. Bash supports this natively as expected, though as always, the syntax isn't really very guessable!

好的,知道该怎么做了。Bash 按预期在本机支持此功能,尽管与往常一样,语法并不是很容易猜测!

Essentially ${string//substring/replacement}returns what you'd image, so you can use

基本上${string//substring/replacement}返回你想要的图像,所以你可以使用

MSG=${MSG//\'/\\'}

To do this. The next problem is that the first regex doesn't work anymore, but that can be replaced with

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

git log -n 1 --pretty=format:'%s'

In the end, I didn't even need to escape them. Instead, I just swapped all the ' in the JSON to \". Well, you learn something every day.

最后,我什至不需要逃避他们。相反,我只是将 JSON 中的所有 ' 交换为 \"。好吧,您每天都会学到一些东西。

回答by polm23

Using Python:

使用 Python:

This solution is not pure bash, but it's non-invasive and handles unicode.

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

json_escape () {
    printf '%s' "" | python -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
}

Note that JSON is part of the standard python libraries and has been for a long time, so this is a pretty minimal python dependency.

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

Or using PHP:

或者使用 PHP:

json_escape () {
    printf '%s' "" | php -r 'echo json_encode(file_get_contents("php://stdin"));'
}

Use like so:

像这样使用:

$ json_escape "ヤホー"
"\u30e4\u30db\u30fc"

回答by chepner

Instead of worrying about how to properly quote the data, just save it to a file and use the @construct that curlallows with the --dataoption. To ensure that the output of gitis correctly escaped for use as a JSON value, use a tool like jqto generate the JSON, instead of creating it manually.

无需担心如何正确引用数据,只需将其保存到文件中并使用该选项允许的@结构即可。为确保正确转义的输出以用作 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'

You can also read directly from standard input using -d @-; I leave that as an exercise for the reader to construct the pipeline that reads from gitand produces the correct payload message to upload with curl.

您还可以使用-d @-;直接从标准输入中读取。我将它作为一个练习留给读者来构造管道,它读出git并产生正确的有效载荷消息上传curl

(Hint: it's jq ... | curl ... -d@- 'https://example.com')

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

回答by jchook

jqcan do this.

jq可以做到这一点。

Lightweight, free, and written in C, jqenjoys widespread community support with over 15k stars on GitHub. I personally find it very speedy and useful in my daily workflow.

轻量级、免费、用 C 语言编写,jqGitHub 上获得了超过 15,000 颗星的广泛社区支持。我个人认为它在我的日常工作流程中非常快速和有用。

Convert string to JSON

将字符串转换为 JSON

jq -aRs . <<< '猫に小判'

To explain,

解释,

  • -ameans "ascii output"
  • -Rmeans "raw input"
  • -smeans "include linebreaks"
  • .means "output the root of the JSON document"
  • <<<passes a string into stdin (bash only?)
  • -a意思是“ascii 输出”
  • -R意思是“原始输入”
  • -s意思是“包括换行符”
  • .意思是“输出 JSON 文档的根”
  • <<<将字符串传递到标准输入中(仅限 bash?)

Git + Grep Use Case

Git + Grep 用例

To fix the code example given by the OP, simply pipe through jq.

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

MSG=`git log -n 1 --format=oneline | grep -o ' .\+' | jq -aRs .`

回答by xsgordon

I was also trying to escape characters in Bash, for transfer using JSON, when I came across this. I found that there is actually a larger list of characters that must be escaped– particularly if you are trying to handle free form text.

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

There are two tips I found useful:

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

  • Use the Bash ${string//substring/replacement}syntax described in this thread.
  • Use the actual control characters for tab, newline, carriage return, etc. In vim you can enter these by typing Ctrl+Vfollowed by the actual control code (Ctrl+Ifor tab for example).
  • 使用${string//substring/replacement}此线程中描述的 Bash语法。
  • 将实际控制字符用于制表符、换行符、回车等。在 vim 中,您可以通过键入Ctrl+V后跟实际控制代码来输入这些字符(例如,Ctrl+I表示制表符)。

The resultant Bash replacements I came up with are as follows:

我想出的 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)

I have not at this stage worked out how to escape Unicode characters correctly which is also (apparently) required. I will update my answer if I work this out.

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

回答by wcy

git log -n 1 --format=oneline | grep -o ' .\+' | jq --slurp --raw-input

The above line works for me. refer to https://github.com/stedolan/jqfor more jqtools

上面的行对我有用。更多工具请参考 https://github.com/stedolan/jqjq

回答by m-szalik

The simplest way is using jshon, a command line tool to parse, read and create JSON.

最简单的方法是使用jshon,一个命令行工具来解析、读取和创建 JSON

jshon -s 'Your data goes here.' 2>/dev/null

jshon -s 'Your data goes here.' 2>/dev/null

回答by user907860

I found something like that :

我发现了类似的东西:

MSG=`echo $MSG | sed "s/'/\\\'/g"`

回答by KirillDE

I had the same idea to send a message with commit message after commit. First i tryed similar was as autor here. But later found a better and simpler solution.

我有同样的想法在提交后发送带有提交消息的消息。首先,我在这里尝试过类似的作者。但是后来找到了一个更好更简单的解决方案。

Just created php file which is sending message and call it with wget. in hooks/post-receive :

刚刚创建的 php 文件正在发送消息并用 wget 调用它。在钩子/接收后:

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

in git.php:

在 git.php 中:

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

And then create JSON and call CURL in PHP style

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

回答by Josh Bode

This is an escaping solution using Perl that escapes backslash (\), double-quote (") and control characters U+0000to U+001F:

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

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