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
4
Answers
Like this:
You then should take care about what you fed in the variable, this have to be valid
JSON
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:
The JSON here is mostly contained within single quotation marks (
'
…'
). But right after opening the pair of literal"
s that will enclose the value ofdata
, 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 ofdata
.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:
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
:Using
--arg
creates a variable insidejq
– I named itdata
– 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
tojq
, andjq
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:Either way you can include the constructed JSON in your
curl
command line like this:Do not generate such JSON by hand. Use a tool like
jq
to do it for you.As an alternative to
jq
andcurl
you could use xidel to generate the JSON and submit the POST-request.With command-line options:
Or with the
x:request()
function in-query:$raw
//raw
returns the raw output, likecurl
. If the API-endpoint returns JSON, then you can use$json
//json
to parse it.