尝试在Bash / Shell POST请求的JSON数据中包含一个动态变量,发送至API端点。

huangapple go评论70阅读模式
英文:

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 
    } 
  ] 
}'

使用 --argjq 中创建一个变量(这里我命名为 data),然后可以使用 $varname 的语法(在这种情况下是 $data)将其包含在表达式中。尽管语法相似,但这不是 shell 的插值;我们将字面文本 $data 传递给 jqjq 本身会用变量的值替换它(这是作为 --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=&quot;helloWorldFunction() {\n echo \&quot;hello world\&quot; \n}&quot;

jq -n --arg s &quot;$stringVar&quot; &#39;{name: &quot;my-project&quot;, files: [{data: $s}]}&#39; |
  curl -i -H &quot;Authorization: Bearer &lt;MY_API_TOKEN&gt;&quot; \
          -H &quot;Content-Type: application/json&quot; \ 
          -H &quot;Accept: application/json&quot; \
          -X POST  \
          -d @- \
          &#39;https://api.example.com/v1/endpoint&#39;

答案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=&quot;...&quot;

curl -i -H &quot;Authorization: Bearer &lt;MY_API_TOKEN&gt;&quot; \
    -H &quot;Content-Type: application/json&quot; \
    -H &quot;Accept: application/json&quot; -X POST &#39;https://api.example.com/v1/endpoint&#39; \
    -d@/dev/stdin &lt;&lt;EOF
{
    &quot;name&quot;: &quot;my-project&quot;,
    &quot;files&quot;: [
        {
            &quot;data&quot;: $stringVar
        },
    ],
}
EOF

You then should take care about what you fed in the variable, this have to be valid JSON

答案4

得分: 0

作为替代jqcurl,您可以使用[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=&#39;helloWorldFunction() {\n echo &quot;hello world&quot; \n}&#39;

xidel -s --variable var=&quot;$stringVar&quot; \
  -H &quot;Authorization: Bearer &lt;MY_API_TOKEN&gt;&quot; \
  -H &quot;Content-Type: application/json&quot; \
  -H &quot;Accept: application/json&quot;
  -d &#39;{serialize(
    {&quot;name&quot;:&quot;my-project&quot;,&quot;files&quot;:array{{&quot;data&quot;:$var}}},
    {&quot;method&quot;:&quot;json&quot;}
  )}&#39; \
  &quot;https://api.example.com/v1/endpoint&quot; \
  -e &#39;$raw&#39;

Or with the x:request() function in-query:

#!/bin/bash

stringVar=&#39;helloWorldFunction() {\n echo &quot;hello world&quot; \n}&#39;

xidel -s --variable var=&quot;$stringVar&quot; -e &#39;
  x:request({
    &quot;headers&quot;:(
      &quot;Authorization: Bearer &lt;MY_API_TOKEN&gt;&quot;,
      &quot;Content-Type: application/json&quot;,
      &quot;Accept: application/json&quot;
    ),
    &quot;post&quot;:serialize(
      {&quot;name&quot;:&quot;my-project&quot;,&quot;files&quot;:array{{&quot;data&quot;:$var}}},
      {&quot;method&quot;:&quot;json&quot;}
    ),
    &quot;url&quot;:&quot;https://api.example.com/v1/endpoint&quot;
  })/raw
&#39;

$raw / /raw returns the raw output, like curl. If the API-endpoint returns JSON, then you can use $json / /json to parse it.

huangapple
  • 本文由 发表于 2023年2月19日 01:56:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/75495304.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定