如何在 bash 变量中添加单引号?

如何在 bash 变量中添加单引号?

我正在尝试调用 API 并希望将一些 curl 默认值设置到单个变量中,以便当我进行多次调用时,它会使用同一组“默认值”。

由于某种原因,curl 无法识别,-H 'Content-type: application/json'而我对为什么无法识别感到困惑。

opts=" -v -H 'Content-type: application/json' "
curl $opts -d '{"hi":1}' https://google.com

以上内容打印出来

$ opts=" -v -H 'Content-type: application/json' "
$ curl $opts -d '{"hi":1}' https://google.com
* Could not resolve host: application                <-------- !!
* Closing connection 0
curl: (6) Could not resolve host: application
* Rebuilt URL to: https://google.com/
*   Trying 172.217.4.174...
* TCP_NODELAY set
* Connected to google.com (172.217.4.174) port 443 (#1)
* TLS 1.2 connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.google.com
* Server certificate: Google Internet Authority G2
* Server certificate: GeoTrust Global CA
> POST / HTTP/1.1
> Host: google.com
> User-Agent: curl/7.54.0
> Accept: */*
> Content-Length: 8
> Content-Type: application/x-www-form-urlencoded    <-------- !!
>
* upload completely sent off: 8 out of 8 bytes

我标记了有问题的两行。Curl 认为 application/json 是主机/路径,因此它不会覆盖 Content-Type。

不过,这样也没问题:

$ curl -v -H 'Content-type: application/json' -d '{"hi":1}' https://google.com
* Rebuilt URL to: https://google.com/
*   Trying 172.217.12.46...
* TCP_NODELAY set
*   Trying 2607:f8b0:4000:813::200e...
* TCP_NODELAY set
* Immediate connect fail for 2607:f8b0:4000:813::200e: No route to host
* Connected to google.com (172.217.12.46) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.google.com
* Server certificate: Google Internet Authority G2
* Server certificate: GeoTrust Global CA
> POST / HTTP/1.1
> Host: google.com
> User-Agent: curl/7.54.0
> Accept: */*
> Content-type: application/json                     <---------- yay
> Content-Length: 8
>
* upload completely sent off: 8 out of 8 bytes

那么我怎样才能让 curl 按照我想要的方式识别参数呢-H?为什么它会这样表现呢?

(是的,我知道我正在使用 Google 作为我的 API 端点并获取 4xx 代码......它只是一个网络服务器,我现在可以对其进行测试以证明我的观点)

答案1

简短回答:参见BashFAQ #50:“我试图将命令放入变量中,但复杂的情况总是失败!”

长答案:将命令(或命令的一部分)放入变量中,然后完整地取出它们,这很复杂。您遇到的基本问题是,shell 在扩展变量引用之前会解析引号,因此将引号放入变量中不会产生任何有用的效果 —— 当它们成为命令行的一部分时,它们已经太晚了,无法发挥预期的效果。

有几种方法可以做到这一点;哪种方法最好取决于您到底想做什么。

选项 1 是使用数组而不是纯文本变量:

opts=(-v -H 'Content-type: application/json')
curl "${opts[@]}" -d '{"hi":1}' https://google.com

语法有点混乱(我上面使用的所有引号、圆括号、方括号等实际上都是正常工作所必需的),并且数组是 bash 的一个功能(并非所有 shell 都可用,因此请务必使用类似#!/bin/bashor 的shebang #!/usr/bin/env bash)。另一方面,如果需要,您可以动态构建选项数组:

opts=(-v -H 'Content-type: application/json')
if [[ -n "$fakeuseragent" ]]; then
    opts+=(-A "$fakeuseragent")
fi
curl "${opts[@]}" -d '{"hi":1}' https://google.com

选项 2 是使用函数来包装curl,并添加您的自定义选项:

mycurl() {
    curl -v -H 'Content-type: application/json' "$@"
}
mycurl -d '{"hi":1}' https://google.com

答案2

也许你可以使用eval这里的命令:

#!/bin/bash

opts=" -v -H 'Content-type: application/json' "

eval curl $opts -d '{"hi":1}' https://google.com

eval-通过连接参数构造命令

eval 实用程序应通过将参数连接在一起来构造命令,每个参数用空间. 构造的命令将被shell读取并执行。

http://www.unix.com/man-page/posix/1posix/eval/


前者的警告curl $opts是,shell 将空格之间的所有元素解释为分隔的参数,如下所示:

curl -v -H "'Content-type:" "application/json'"

这当然不是你想要的。正确eval评估字符串。$opts

相关内容