如何在带有 bash 的 CURL 请求中使用变量?

Posted

技术标签:

【中文标题】如何在带有 bash 的 CURL 请求中使用变量?【英文标题】:How to use a variable in a CURL request with bash? 【发布时间】:2016-09-26 03:50:52 【问题描述】:

目标:

我正在使用 bash CURL 脚本连接到 Cloudflare APIv4。目标是更新 A 记录。我的脚本:

   # Get current public IP
      current_ip=curl --silent ipecho.net/plain; echo

   # Update A record
      curl -X PUT "https://api.cloudflare.com/client/v4/zones/ZONEIDHERE/dns_records/DNSRECORDHERE" \
        -H "X-Auth-Email: EMAILHERE" \
        -H "X-Auth-Key: AUTHKEYHERE" \
        -H "Content-Type: application/json" \
        --data '"id":"ZONEIDHERE","type":"A","name":"example.com","content":"'"$current_ip"'","zone_name":"example.com"'

问题:

当我在脚本中调用 current_ip 变量时,它不会被打印出来。输出将是 "content" : "" 而不是 "content" : "1.2.3.4"

我使用了other*** 帖子,我正在尝试遵循他们的示例,但我认为我仍然做错了什么,只是不知道是什么。 :(

【问题讨论】:

【参考方案1】:

从 shell 脚本编辑 JSON 的可靠方法是使用 jq:

# set shell variables with your contents
email="yourEmail"
authKey="yourAuthKey"
zoneid="yourZoneId"
dnsrecord="yourDnsRecord"

# make sure we show errors; --silent without --show-error can mask problems.
current_ip=$(curl --fail -sS ipecho.net/plain) || exit

# optional: template w/ JSON content that won't change
json_template='"type": "A", "name": "example.com"'

# build JSON with content that *can* change with jq
json_data=$(jq --arg zoneid "$zoneid" \
               --arg current_ip "$current_ip" \
               '.id=$zoneid | .content=$current_ip' \
               <<<"$json_template")

# ...and submit
curl -X PUT "https://api.cloudflare.com/client/v4/zones/$zoneid/dns_records/$dnsrecord" \
  -H "X-Auth-Email: $email" \
  -H "X-Auth-Key: $authKey" \
  -H "Content-Type: application/json" \
  --data "$json_data"

【讨论】:

我认为使用 jq 是解决问题的好方法!代码也很干净直接,谢谢你的代码!但是,我想尝试继续使用没有附加组件的普通 bash,甚至(如果可能)不使用 python 或 perl。我没有在我的帖子中提到这一点,所以在接受这个作为答案之前,我仍在寻找一个非 jq 选项。 +1 解决方案 我在使用带有 = 分配的 arg 语法时遇到了一些问题。它没有替换/添加指定的键。它使用--arg zoneid "$zoneid"(不带等号)对我有用。 @AndreasJägle,感谢您的修复!我不知道为什么这个问题没有更早地被发现——也许以前的版本对不严格匹配手册的命令行使用更宽松? ——但这种改变绝对是正确的。【参考方案2】:

正如 Charles Duffy 的回答所暗示的那样,为此使用 jq 是一个非常好的主意。但是,如果您不能或不想在此处安装 jq,您可以使用普通的 POSIX shell 来执行此操作。

#!/bin/sh
set -e

current_ip="$(curl --silent --show-error --fail ipecho.net/plain)"
echo "IP: $current_ip"

# Update A record
curl -X PUT "https://api.cloudflare.com/client/v4/zones/ZONEIDHERE/dns_records/DNSRECORDHERE" \
    -H "X-Auth-Email: EMAILHERE" \
    -H "X-Auth-Key: AUTHKEYHERE" \
    -H "Content-Type: application/json" \
    --data @- <<END;

    "id": "ZONEIDHERE",
    "type": "A",
    "name": "example.com",
    "content": "$current_ip",
    "zone_name": "example.com"

END

【讨论】:

这种情况的主要问题是,如果您的内容在不需要引用或转义的情况下无法从字面上替换为 JSON 文档,但对于 IP 地址来说不太可能发生这种情况,所以它是一个合理的妥协点。 ...我可能会在curl 的结果的分配末尾添加一个|| exit,这样我们就不会在出现故障时继续进行,或者@987654325 @(或者,更确切地说,因为您使用的是#!/bin/sh[ -n "$current_ip" ] || exit)在后续行; --fail 确保 curl 的退出状态反映了失败,但如果 shell 未使用 -e 运行,它不一定会按照退出状态运行。 是的,完全正确。将 JSON 作为文本操作时应该非常小心,并尽可能避免使用它。即使您的 *nix 机器没有 jq,它也可能有 Perl 或 Python。如有疑问,请使用其中之一来准备您的 JSON。 我在第一个curl 命令之前添加了set -e。我从一开始就打算这样做,但完全忘记了。 (另外,我采纳了您的--show-error 建议——这对单独使用--silent 的改进。谢谢!)

以上是关于如何在带有 bash 的 CURL 请求中使用变量?的主要内容,如果未能解决你的问题,请参考以下文章

如何在bash脚本中传递变量的双引号值作为curl命令的参数?

HTTP入门(一):在Bash中curl查看请求与响应

如何在curl PUT请求的主体中使用环境变量?

如何将curl的输出捕获到bash中的变量[重复]

如何在 bash 中使用带有特殊字符的变量? [复制]

HTTP post/API 请求在 bash 上从 CURL 发送时有效,从 Apache http 失败