[英]Cannot use variable inside json --data
I have a working API (linode) to update a domain.我有一个可用的 API (linode) 来更新域。 So, below is a normal API call that work just fine to update data:
因此,下面是一个正常的 API 调用,可以很好地更新数据:
#!/bin/bash
# hardcoded data for testing
LINODE_API_KEY=1234
domain_id=1931316
domain_name="abx.com"
domain_type="master"
domain_email="hello@abx.com"
domain_ttl=30
# Update the domain
curl -H "Content-Type: application/json" \
-H "Authorization: Bearer ${LINODE_API_KEY}" \
-X PUT -d "{
\"domain\": \"${domain_name}\", \"type\": \"${domain_type}\", \"soa_email\": \"${domain_email}\", \"ttl_sec\": ${domain_ttl}
}" "https://api.linode.com/v4/domains/${domain_id}"
When I executed the above update API, it's working fine and I get the json response as:当我执行上面的更新 API 时,它工作正常,我得到的 json 响应如下:
{"id": 1931316, "type": "master", "domain": "abx.com", "tags": [], "group": "", "status": "active", "errors": "", "description": "", "soa_email": "hello@abx.com", "retry_sec": 0, "master_ips": [], "axfr_ips": [], "expire_sec": 0, "refresh_sec": 0, "ttl_sec": 30, "created": "2022-12-13T09:01:01", "updated": "2022-12-14T03:26:27"}
But the problem is I want to use variable inside the data.但问题是我想在数据中使用变量。 So I change the working code above into this (with extra data that I want to pass):
所以我将上面的工作代码更改为这个(带有我想传递的额外数据):
#!/bin/bash
# hardcoded data for testing
LINODE_API_KEY=1234
domain_id=1931316
domain_name="abx.com"
domain_type="master"
domain_email="hello@abx.com"
domain_ttl=30
# This value must be provided first
if [ -z "${domain_name}" ]; then
echo "You must provide domain name"
exit 1
else
change_domain_name="\\\"domain\\\": \\\"${domain_name}\\\""
fi
if [ -n "${domain_type}" ]; then
change_domain_type=", \\\"type\\\": \\\"${domain_type}\\\""
else
change_domain_type=""
fi
if [ -n "${soa_email}" ]; then
change_domain_email=", \\\"soa_email\\\": \\\"${domain_email}\\\""
else
change_domain_email=""
fi
if [ -n "${domain_ttl}" ]; then
change_domain_ttl=", \\\"ttl_sec\\\": ${domain_ttl}"
else
change_domain_ttl=""
fi
update_string="${change_domain_name}${change_domain_type}${change_domain_email}${change_domain_ttl}"
# Update the domain
curl -H "Content-Type: application/json" \
-H "Authorization: Bearer ${LINODE_API_KEY}" \
-X PUT -d "{
${update_string} # THE PROBLEM IS HERE WHEN USING THIS VARIABLE
}" "https://api.linode.com/v4/domains/${domain_id}"
The API will complain about Invalid JSON API 会抱怨 Invalid JSON
{"errors": [{"reason": "Invalid JSON"}]}
But when I use echo ${update_string}
variable, I will get the same data syntax like I use so why does it complain this is invalid?但是当我使用
echo ${update_string}
变量时,我会得到与我使用的相同的数据语法,那么为什么它会抱怨这是无效的呢?
I can even copy paste back the echo result above inside the -d data and it's working fine.我什至可以将上面的回声结果复制粘贴回 -d 数据中,并且工作正常。
I rolled back my question to the original as to explain why I use the above method instead of creating jq --arg
as suggested @Arnaud Valmary.我将我的问题回滚到原始问题,以解释为什么我使用上述方法而不是按照@Arnaud Valmary 的建议创建
jq --arg
--arg 。
So for example here I only want to pass value domain_name and domain_ttl.例如,这里我只想传递值 domain_name 和 domain_ttl。 So the value of the update string would be like this:
所以更新字符串的值将是这样的:
update_string="${change_domain_name}${change_domain_ttl}" update_string="${change_domain_name}${change_domain_ttl}"
where the others were empty.其他人是空的。 So, I'm not sure how to achieve this using
jq --arg
所以,我不确定如何使用
jq --arg
来实现这一点
In brief, if domain_type="" or domain_type is empty, I don't want this variable to be in the --arg options, so user have a choice not to update this value.简而言之,如果 domain_type="" 或 domain_type 为空,我不希望此变量位于 --arg 选项中,因此用户可以选择不更新此值。
It's better to build JSON data with a dedicated tool like jq
.最好使用
jq
等专用工具构建 JSON 数据。 Bash string construction is hazardous. Bash 字符串构造是危险的。
#! /usr/bin/env bash
# hardcoded data for testing
declare LINODE_API_KEY=1234
declare domain_id=1931316
declare domain_name="abx.com"
declare domain_type="master"
declare domain_email="hello@abx.com"
declare domain_ttl=30
declare json_query_data='{}'
# This value must be provided first
if [ -z "${domain_name}" ]; then
echo "You must provide domain name"
exit 1
else
# shellcheck disable=SC2016
json_query_data=$(jq --arg domain "${domain_name}" '.domain |= $domain' <<<"${json_query_data}")
fi
if [ -n "${domain_type}" ]; then
# shellcheck disable=SC2016
json_query_data=$(jq --arg type "${domain_type}" '.type |= $type' <<<"${json_query_data}")
fi
if [ -n "${domain_email}" ]; then
# shellcheck disable=SC2016
json_query_data=$(jq --arg soa_email "${domain_email}" '.soa_email |= $soa_email' <<<"${json_query_data}")
fi
if [ -n "${domain_ttl}" ]; then
# shellcheck disable=SC2016
json_query_data=$(jq --argjson ttl_sec "${domain_ttl}" '.ttl_sec |= $ttl_sec' <<<"${json_query_data}")
fi
# Update the domain
curl -H "Content-Type: application/json" \
-H "Authorization: Bearer ${LINODE_API_KEY}" \
-X PUT \
-d "${json_query_data}" \
--url "https://api.linode.com/v4/domains/${domain_id}"
cURL command is: cURL 命令是:
curl -H 'Content-Type: application/json' -H 'Authorization: Bearer 1234' -X PUT -d '{"domain":"abx.com","type":"master","soa_email":"hello@abx.com","ttl_sec":30}' --url 'https://api.linode.com/v4/domains/1931316'
This is an error-prone endeavor.这是一项容易出错的工作。 You're better off using a JSON-parser like xidel to build your JSON data:
你最好使用像xidel这样的 JSON 解析器来构建你的 JSON 数据:
$ xidel -s \
--variable name="$domain_name" \
--variable type="$domain_type" \
--variable email="$domain_email" \
--variable ttl="$domain_ttl" \
-e '{
"domain":$name,
"type"?:if ($type="") then () else $type,
"soa_email"?:if ($email="") then () else $email,
"ttl_sec"?:if ($ttl="") then () else int($ttl)
}'
{
"domain": "abx.com",
"type": "master",
"soa_email": "hello@abx.com",
"ttl_sec": 30
}
If only $domain_name
was declared, then in this case only {"domain": "abx.com"}
would be returned.如果只声明了
$domain_name
,那么在这种情况下只会返回{"domain": "abx.com"}
。
Generate the (serialized) JSON data with xidel
, export as a variable and execute curl
with it:使用
xidel
生成(序列化的)JSON 数据,导出为变量并使用它执行curl
:
#!/bin/bash
LINODE_API_KEY=1234
domain_id=1931316
domain_name="abx.com"
domain_type="master"
domain_email="hello@abx.com"
domain_ttl=30
if [ -z "${domain_name}" ]; then
echo "You must provide domain name"
exit 1
fi
eval "$(
xidel -s \
--variable name="$domain_name" \
--variable type="$domain_type" \
--variable email="$domain_email" \
--variable ttl="$domain_ttl" \
-e '
json_query_data:=serialize(
{
"domain"?:$name,
"type"?:if ($type="") then () else $type,
"soa_email"?:if ($email="") then () else $email,
"ttl_sec"?:if ($ttl="") then () else int($ttl)
},
{"method":"json"}
)
' --output-format=bash
)"
curl \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${LINODE_API_KEY}" \
-X PUT \
-d "${json_query_data}" \
--url "https://api.linode.com/v4/domains/${domain_id}"
Generate and send the JSON data and parse the returning JSON data with xidel
(making curl
superfluous):生成并发送 JSON 数据并使用
xidel
解析返回的 JSON 数据(使curl
变得多余):
#!/bin/bash
LINODE_API_KEY=1234
domain_id=1931316
domain_name="abx.com"
domain_type="master"
domain_email="hello@abx.com"
domain_ttl=30
# This value must be provided first
if [ -z "${domain_name}" ]; then
echo "You must provide domain name"
exit 1
fi
xidel -s \
--variable name="$domain_name" \
--variable type="$domain_type" \
--variable email="$domain_email" \
--variable ttl="$domain_ttl" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${LINODE_API_KEY}" \
--method PUT \
-d '{
serialize(
{
"domain"?:$name,
"type"?:if ($type="") then () else $type,
"soa_email"?:if ($email="") then () else $email,
"ttl_sec"?:if ($ttl="") then () else int($ttl)
},
{"method":"json"}
)
}' \
"https://api.linode.com/v4/domains/${domain_id}" \
-e '$json'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.