英文:
Trying to include a dynamic variable within JSON data of a Bash / Shell POST request to API endpoint
问题
抱歉,由于代码部分不需要翻译,以下是你需要的翻译部分:
你想使用 Bash 提交一个 POST 请求,其中包括 JSON 数据,其中的一个变量等于随机字符串。我通过解析一个内容可能变化的文件来动态获取这个字符串……这个文件可能包含正则表达式字符和换行符。
我将在这里提供一个示例字符串,其中包括一个使用 curl 请求成功与我要提交请求的 API 的示例。我只能够在 JSON 数据中硬编码字符串,并不能像使用 stringVar
这样将变量赋值给字符串然后在 JSON 数据中使用这个变量来成功完成请求。我确实需要一些帮助,找出我错在哪里。
我的工作 Shell 脚本大致如下:
这是有效的,但是我需要将 data
的值从字符串 helloWorldFunction() {\n echo "hello world" \n} 更改为一个变量。
我已经尝试了不同的方式在 JSON 内容中设置变量,根据其他问题中的建议。例如,我尝试更改我的 Shell 脚本如下:
我尝试设置变量,像这样:
希望以上能帮到你。
英文:
I am trying to submit a POST request using Bash that includes JSON data with a variable equal to that of a random string. I get the string dynamically by parsing a file which can vary in content... and may contain regex characters and also new lines.
I will provide an example string here with a curl request that works successfully with the API I am posting this request to. I can only get the request to go through with the string hardcoded into the JSON data and not while assigning a variable to the string like for instance stringVar
and using the variable in the JSON data. I could sure use some help where I am messing this up
my working shell script looks something like this
#!/bin/bash
curl -i -H "Authorization: Bearer <MY_API_TOKEN>" -H "Content-Type: application/json" -H "Accept: application/json" -X POST 'https://api.example.com/v1/endpoint' -d '{
"name": "my-project",
"files": [
{
"data": "helloWorldFunction() {\n echo \"hello world\" \n}"
},
],
}'
This works, however I need to change data's value from the string
helloWorldFunction() {\n echo "hello world" \n}
to a variable
I have tried settings the variable in different ways in the JSON content from reading suggestions on other questions. For instance I have tried tried changing my shell script to
#!/bin/bash
stringVar="helloWorldFunction() {\n echo \"hello world\" \n}"
curl -i -H "Authorization: Bearer <MY_API_TOKEN>" -H "Content-Type: application/json" -H "Accept: application/json" -X POST 'https://api.example.com/v1/endpoint' -d '{
"name": "my-project",
"files": [
{
"data": "${stringVar}"
},
],
}'
i have tried setting the variable like this
"${stringVar}" | turns into ${stringVar}
"$stringVar" | turns into "$stringVar"
and
"'${stringVar}'"
"'$stringVar'"
both seem to return this error
{"error":{"code":"bad_request","message":"Invalid JSON"}}curl: (3) unmatched brace in URL position 1:
{\n
and
stringVar
stringVar
$stringVar
"'"$stringVar"'"
""$stringVar""
${stringVar}
all seem to return this error
{"error":{"code":"bad_request","message":"Invalid JSON"}}
Ahh any help on what I am doing wrong would be great.
Thanks in advance y'all
答案1
得分: 1
为了插值变量的值,你需要将字符串用双引号("
)括起来,但 JSON 也需要字面上的双引号。
最简单的解决方案可能是使用 here-document 将数据传输到 curl
的标准输入,就像 @Gilles Quénot 的回答中所示。但你仍然可以通过命令行传递它;你只需小心处理引号。
以下是一种方法:
curl ... -d ''{
"name": "my-project",
"files": [
{
"data": "'"$stringVar"'"
}
]
}'
这里的 JSON 大部分包含在单引号 ('
...'
) 中。但在打开将包围 data
值的字面双引号对之后,我们关闭单引号并切换我们的 shell 引号模式为双引号,以便包括 $stringVar
的值。在围绕该扩展关闭双引号后,我们再次使用单引号表示 JSON 的其余部分,从包围 data
值的字面双引号开始。
在使用 +
进行字符串连接的语言中,看起来像是 '... "data": "' + "$stringVar" + '"... '
,但在 shell 中,你只需将字符串放在一起,而无需连接操作符。
作为另一种选择,你可以将整个内容放在双引号中,但是这样需要使用反斜杠来包含 JSON 中的字面双引号:
curl ... -d "{
\"name\": \"my-project\",
\"files\": [
{
\"data\": \"$stringVar\"
}
]
}"
因此,如果你从普通的 JSON 开始,这需要更多的更改;在我看来,这也显得更混乱。
你也可以使用了解如何构建 JSON 的工具,并让它处理引号等问题。以下是一种使用 jq
构建的方法:
jq -n --arg data "$stringVar" ''{
"name": "my-project",
"files": [
{
"data": $data
}
]
}'
使用 --arg
在 jq
中创建一个变量(这里我命名为 data
),然后可以使用 $varname
的语法(在这种情况下是 $data
)将其包含在表达式中。尽管语法相似,但这不是 shell 的插值;我们将字面文本 $data
传递给 jq
,jq
本身会用变量的值替换它(这是作为 --arg
的第二个参数传递的)。
还有另一个名为 jo
的工具,它不是操作 JSON 而是生成 JSON,通过在 shell 中更容易生成的输入。以下是使用它构建所需对象的一种方法:
jo name=my-project files="$(jo -a "$(jo data="$stringVar")")"
无论哪种方式,你都可以像这样将构建的 JSON 包含在 curl
命令行中:
curl ... -d "$(jo 或 jq 命令放在这里)"
英文:
In order to interpolate the value of a variable, you need to enclose the string in double-quotes("
), but the JSON also requires literal double-quotes.
The easiest solution is probably to use a here-document to feed the data into curl
's standard input, as in @Gilles Quénot's answer. But you can still pass it in via the command line; you just have to be careful with the quotes.
This is one way:
curl ... -d '{
"name": "my-project",
"files": [
{
"data": "'"$stringVar"'"
}
]
}'
The JSON here is mostly contained within single quotation marks ('
...'
). But right after opening the pair of literal "
s that will enclose the value of data
, we close the single quotes and switch our shell quotation mode to double quotes in order to include the value of $stringVar
. After closing the double quotes around that expansion, we go back into single quotes for the rest of the JSON, starting with closing the literal double-quotes around the value of data
.
In a language that used +
for string concatenation, it would look like '... "data": "' + "$stringVar" + '"... '
, but in the shell you just put the strings next to each other with no operator to concatenate them.
As an alternative, you could put the whole thing in double-quotes, but then you need backslashes to include the literal double quotes that are part of the JSON:
curl ... -d "{
\"name\": \"my-project\",
\"files\": [
{
\"data\": \"$stringVar\"
}
]
}"
So that requires a lot more changes if you're starting from plain JSON; it also looks messier, IMO.
You can also use a tool that knows how to build JSON and let it worry about quoting etc. Here's one way to build it with jq
:
jq -n --arg data "$stringVar" '{
"name": "my-project",
"files": [
{
"data": $data
}
]
}'
Using --arg
creates a variable inside jq
– I named it data
– which can then be included in an expression with the syntax $varname
($data
in this case). Despite the similarity of syntax, that's not a shell interpolation; we're passing the literal text $data
to jq
, and jq
itself is what replaces it with the value of the variable (which was passed as the second argument to --arg
).
There's another tool called jo
, which doesn't manipulate JSON but rather produces it, from input that is easier to generate in the shell. Here's one way to construct the desired object with it:
jo name=my-project files="$(jo -a "$(jo data="$stringVar")")"
Either way you can include the constructed JSON in your curl
command line like this:
curl ... -d "$(jo or jq command goes here)"
答案2
得分: 1
不要手动生成这样的JSON。使用像jq
这样的工具来为您生成它。
#!/bin/bash
stringVar="helloWorldFunction() {
echo \"hello world\"
}"
jq -n --arg s "$stringVar" '{name: "my-project", files: [{data: $s}]}' |
curl -i -H "Authorization: Bearer <MY_API_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application json" \
-X POST \
-d @- \
'https://api.example.com/v1/endpoint'
英文:
Do not generate such JSON by hand. Use a tool like jq
to do it for you.
#!/bin/bash
stringVar="helloWorldFunction() {\n echo \"hello world\" \n}"
jq -n --arg s "$stringVar" '{name: "my-project", files: [{data: $s}]}' |
curl -i -H "Authorization: Bearer <MY_API_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-X POST \
-d @- \
'https://api.example.com/v1/endpoint'
答案3
得分: 0
像这样:
#!/bin/bash
stringVar="..."
curl -i -H "Authorization: Bearer <MY_API_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application json" -X POST 'https://api.example.com/v1/endpoint' \
-d@/dev/stdin <<EOF
{
"name": "my-project",
"files": [
{
"data": $stringVar
}
]
}
EOF
然后您应该注意要将有效的 JSON 放入变量中。
英文:
Like this:
#!/bin/bash
stringVar="..."
curl -i -H "Authorization: Bearer <MY_API_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" -X POST 'https://api.example.com/v1/endpoint' \
-d@/dev/stdin <<EOF
{
"name": "my-project",
"files": [
{
"data": $stringVar
},
],
}
EOF
You then should take care about what you fed in the variable, this have to be valid JSON
答案4
得分: 0
作为替代jq
和curl
,您可以使用[tag:xidel]生成JSON并提交POST请求。
使用命令行选项:
stringVar='helloWorldFunction() {
echo "hello world"
}'
xidel -s --variable var="$stringVar" \
-H "Authorization: Bearer <MY_API_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application json"
-d '{serialize(
{"name":"my-project","files":array{"data":$var}},
{"method":"json"}
)}'
"https://api.example.com/v1/endpoint" \
-e '$raw'
或者使用查询中的x:request()
函数:
stringVar='helloWorldFunction() {
echo "hello world"
}'
xidel -s --variable var="$stringVar" -e '
x:request({
"headers":(
"Authorization: Bearer <MY_API_TOKEN>",
"Content-Type: application/json",
"Accept: application/json"
),
"post":serialize(
{"name":"my-project","files":array{"data":$var}},
{"method":"json"}
),
"url":"https://api.example.com/v1/endpoint"
})/raw
'
$raw
/ /raw
返回原始输出,类似于curl
。如果API端点返回JSON,则可以使用$json
/ /json
来解析它。
英文:
As an alternative to jq
and curl
you could use [tag:xidel] to generate the JSON and submit the POST-request.
With command-line options:
#!/bin/bash
stringVar='helloWorldFunction() {\n echo "hello world" \n}'
xidel -s --variable var="$stringVar" \
-H "Authorization: Bearer <MY_API_TOKEN>" \
-H "Content-Type: application/json" \
-H "Accept: application/json"
-d '{serialize(
{"name":"my-project","files":array{{"data":$var}}},
{"method":"json"}
)}' \
"https://api.example.com/v1/endpoint" \
-e '$raw'
Or with the x:request()
function in-query:
#!/bin/bash
stringVar='helloWorldFunction() {\n echo "hello world" \n}'
xidel -s --variable var="$stringVar" -e '
x:request({
"headers":(
"Authorization: Bearer <MY_API_TOKEN>",
"Content-Type: application/json",
"Accept: application/json"
),
"post":serialize(
{"name":"my-project","files":array{{"data":$var}}},
{"method":"json"}
),
"url":"https://api.example.com/v1/endpoint"
})/raw
'
$raw
/ /raw
returns the raw output, like curl
. If the API-endpoint returns JSON, then you can use $json
/ /json
to parse it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论