如何在bashvariables中添加单引号?

我试图调用一个API,并希望设置一个curl默认值为一个variables,所以当我做多个调用时,它使用相同的一组“默认值”。

出于某种原因,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 

我在有问题的地方标记了2行。 Curl认为application / json是一个主机/path,并且不覆盖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参数呢? 为什么它会这样呢?

(是的,我知道我使用谷歌作为我的API端点和获取4xx代码..它只是一个networking服务器,我现在可以testing,以表明我的观点)

简短的回答:参见BashFAQ#50:“我试图把一个命令放在一个variables中,但是复杂的情况总是失败的!” 。

长的回答:把命令(或命令的一部分)变成variables,然后把它们恢复完整是很复杂的。 你遇到的基本问题是shell在扩展variables引用之前parsing引号,所以把引号放在variables中并没有什么用处 – 当它们成为命令行的一部分的时候,对它们来说已经太迟了有其预期的效果。

有几种方法可以做到这一点; 这最好取决于你想要做的事情。

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

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

语法有点混乱(所有的引号,括号,括号等我上面实际上是必要的,因为它是正确的),数组是一个bashfunction(不是在所有shell中都可用,所以一定要使用像#!/bin/bash#!/usr/bin/env bash )。 另一方面,如果需要,可以dynamic构build选项数组:

 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 

也许你可以在这里使用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正确评估string$opts