防止bash将单引号添加到变量输出

7
问题: 我正在编写一个使用 curl 执行多个 HTTP 请求的脚本,我想将请求头添加到变量 CURL_HEADERS 中,以便不必经常输入它们。但是当我在 curl 命令中回显 CURL_HEADERS 变量时,单引号出现在我不想要它们的地方。如何防止这种情况?(为了更清晰起见,下面的代码进行了简化) 代码:
#!/usr/bin/env bash
AUTH_KEY='1234'
set -x
CURL_HEADERS='-H "Authorization: Basic '${AUTH_KEY}'" -H "Content-Type: application/json"'
echo "${CURL_HEADERS}"
curl -s $(echo "${CURL_HEADERS}") 'http://www.example.org' > /dev/null
set +x

期望输出:

+ CURL_HEADERS='-H "Authorization: Basic 1234" -H "Content-Type: application/json"'
+ echo '-H "Authorization: Basic 1234" -H "Content-Type: application/json"'
-H "Authorization: Basic 1234" -H "Content-Type: application/json"
++ echo '-H "Authorization: Basic 1234" -H "Content-Type: application/json"'
+ curl -s -H "Authorization: Basic 1234" -H "Content-Type: application/json" http://www.example.org
+ set +x

实际输出

+ CURL_HEADERS='-H "Authorization: Basic 1234" -H "Content-Type: application/json"'
+ echo '-H "Authorization: Basic 1234" -H "Content-Type: application/json"'
-H "Authorization: Basic 1234" -H "Content-Type: application/json"
++ echo '-H "Authorization: Basic 1234" -H "Content-Type: application/json"'
+ curl -s -H '"Authorization:' Basic '1234"' -H '"Content-Type:' 'application/json"' http://www.example.org
+ set +x

你意识到以 + 开头的行会在 shell 处理后打印出命令吗?单引号不会出现在输出中。手册对此并没有详细说明,但我认为这是 shell 表示“这是一个逐字字符串,不会再进行扩展或分割”的方式。而且,双引号的存在表明了这一点(它们是字符串的一部分,而不是字符串定界符(至少对于 shell 是这样的))。 - Peter - Reinstate Monica
@peter-a-schneider请尊重他人,我认为OP知道set -x的作用。此外,他正确地识别了他失败的curl命令的原因,然后明确地询问如何防止它。只需运行OP的代码即可复制。这些单引号可能对shell不可见,但它们确实显示了shell如何读取它们。 - Will Barnwell
值得注意的是,在圆括号中使用命令替换会创建一个新的“引用上下文”,这使得生活变得更加轻松,也可能在此处如此(尽管,正如威尔在他的帖子中正确地观察到的那样,回显变量是多余的,可以直接省略)。因此,可以编写"$(echo "${CURL_HEADERS}")",在命令替换中引用参数以及整体结果。双引号已正确配对,并且外部双引号(而不是始终允许在双引号周围使用的单引号)仍使参数变量成为可扩展的对象。 - Peter - Reinstate Monica
1
@PeterA.Schneider:“$(echo "${CURL_HEADERS}")”与“${CURL_HEADERS}”完全相同(除了对于bash来说更加繁琐),并且它们都存在同样的问题:它们只生成一个参数;而OP希望有四个参数。命令替换并不能像魔法一样重新解释字符串,使其成为bash命令的一部分。内部引号仍然只是普通字符。 - rici
显示剩余5条评论
2个回答

11

一个相当简单的解决方案是使用bash数组来存储您想要传递的四个参数:

CURL_HEADERS=(
             '-H' "Authorization: Basic ${AUTH_KEY}"
             '-H' 'Content-Type: application/json'
)

curl -s "${CURL_HEADERS[@]}" 'http://www.example.org' > /dev/null

与标量变量不同,它们只是普通字符的普通字符串,无论包含多少引号,数组都是由一系列字符串列表组成,每个字符串都与其他字符串有所区别。在这个意义上,Bash 就像几乎所有其他编程语言一样。

这个问题以及我提出的解决方案以及其他几个解决方案,在 Bash FAQ 条目 50(我试图将一个命令放入变量中,但复杂情况总是失败!)中有详细描述,值得仔细阅读。(链接来自@John1024 的评论。)


0
提议的数组是一种好的设计方法,但curl仍然会向已经包含双引号的数组项添加单引号,从而使标头无效。

1
不是的。单引号是bash的“-x”选项的一部分,它试图明确地显示元素。它们不在数据本身中。 - rici

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