我正在尝试在文件curl
内使用 x-www-form-urlencode 运行 POST JSON 数据docker-compose
。对于这个例子,我正在使用这个公共网站,我需要做出如下响应
# sh -c 'curl http://httpbin.org/post -F "json={\"key\": \"value\"}"'
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{\"key\": \"value\"}"
}, ...
这对于外部的单引号工作得很好,但我需要双引号,因为我内部会有变量。所以这个命令不起作用,我无法找出转义嵌套引号的正确语法。
# sh -c "curl http://httpbin.org/post -F "json={\"key\": \"$VAR\"}""
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{key:"
},
答案1
您想要插入到发送到的参数中的数据curl
是对 JSON 文档进行编码的 JSON 编码字符串。
该字符串可以单独创建,如下所示:
json_string=$( jq -n --arg 'my key' 'my "value"' '$ARGS.named|@json' )
通过使用 JSON 感知工具jq
将数据转换为 JSON 编码的字符串,我们确保字符串的内容既是有效的 JSON 字符串,又可以解码为包含给定键、my key
和的有效 JSON 文档。价值,my "value"
。
上面的确切命令会将字符串分配"{\"my key\":\"my \\\"value\\\"\"}"
给json_string
.
然后我们可以curl
在参数中直接使用这个字符串进行调用,如下所示,
curl 'http://httpbin.org/post' -F "json=$json_string"
sh -c
...或者,我们可以通过将字符串作为参数传递给该脚本,从内联脚本中调用它,如下所示,
sh -c 'curl "http://httpbin.org/post" -F "json=$1"' sh "$json_string"
这两种调用方式中的任何一种curl
都会得到如下所示的回复:
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{\"my key\":\"my \\\"value\\\"\"}"
},
"headers": {
"Accept": "*/*",
"Content-Length": "160",
"Content-Type": "multipart/form-data; boundary=------------------------f805cf070f665e7e",
"Host": "httpbin.org",
"User-Agent": "curl/7.84.0",
"X-Amzn-Trace-Id": "Root=1-83012651-2995681c270059da2906c40f"
},
"json": null,
"origin": "xxx.xxx.xxx.xxx",
"url": "http://httpbin.org/post"
}
将 JSON 文档编码为 JSON 字符串并不是严格必要的,因为curl
似乎是自行执行此操作,因此您可以使用
json_string=$( jq -n -c --arg 'my key' 'my "value"' '$ARGS.named' )
...创建 JSON 字符串,或者,如果您碰巧jo
安装了,则较短
json_string=$( jo 'my key'='my "value"' )
答案2
像这样吗?
$ var=hello
$ sh -c "curl http://httpbin.org/post -F 'json={\"key\": \"$var\"}'"
{
"args": {},
"data": "",
"files": {},
"form": {
"json": "{\"key\": \"hello\"}"
},
注释:
$ sh -c "curl http://httpbin.org/post -F 'json={\"key\": \"$var\"}'"
1 2 3 3 34 3 21
(1) 外部双引号,(2) 单引号,不是双引号内特殊,因此无需转义,(3) 内部双引号为外部双引号转义。 (4) 在运行之前,在外部双引号内进行变量扩展sh -c
(请注意,变量值内的单引号会导致内壳出现问题,并且那里的双引号会扰乱 JSON 语法)。
如果sh
是 Bash,并且您使用 运行它-x
,您将看到它运行的内容是这样的:
+ curl http://httpbin.org/post -F 'json={"key": "hello"}'
2 3 3 3 3 2
这与所看到的几乎完全相同sh -c
,其中 (2) 是带引号的字符串,(3) 是该字符串中的非特殊双引号。
(我说“在 Bash 中”,因为 Dash 的set -x
输出并不明确。在 Bash 中,一般来说,-x
重做引用的输出,例如,如果您给出命令echo "foo bar"
,它会将其显示为echo 'foo bar'
。但这并没有真正改变任何内容特殊案例。)
答案3
Heredocs 让这个引用地狱变得更容易管理
sh <<END_SCRIPT
curl http://httpbin.org/post -F 'json={"key": "$VAR"}'
END_SCRIPT
Heredoc 本身没有被引用,因此变量将被替换。
如果VAR="foo bar"
,我们得到
...
"form": {
"json": "{\"key\": \"foo bar\"}"
},
...
您唯一需要担心的是变量值是否包含引号。
我们VAR='She said "Hello"'
看到这个无效的 JSON
...
"form": {
"json": "{\"key\": \"She said \"Hello\"\"}"
},
...
我们可以使用 shell 参数扩展来转义内部引号:
sh <<END_SCRIPT
curl http://httpbin.org/post -F 'json={"key": "${VAR//\"/\\\"}"}'
END_SCRIPT
以便
...
"form": {
"json": "{\"key\": \"She said \\\"Hello\\\"\"}"
},
...