在带引号的字符串中转义引号

在带引号的字符串中转义引号

我正在尝试在文件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\\\"\"}"
  },
...

相关内容