Expand variable inside curly braces, inside single quotes, inside double quotes - bash

I'm trying to write a bash script that takes a variable and populates it inside a somewhat complex string and I can't figure out how to get it to work.
I have the following bash code..
PWD="foobar"
curl -XPOST "localhost/api/user/bob" -H 'Content-Type: application/json' -d '{"password" : "${PWD}"}
what I want to have happen is obviously this:
curl -XPOST "localhost/api/user/bob" -H 'Content-Type: application/json' -d '{"password" : "foobar"}
but none of the iterations and expansion "tricks" I know seem to work because of the braces and the single and double quotes.
I've tried
$PWD
${PWD}
Both to no avail.

You need to use double quotes to allow the $PWD to expand. (The braces are irrelevant here.)
-d "{\"password": \"$password\"}"
Better yet, though, use something like jq to generate JSON so that you can be sure everything is quoted correctly without shell interference.
-d "$(jq -n --arg p "$password" '{password: $p}')"

Related

Curl command issue in bash script because of string variable containing quotes [duplicate]

This question already has answers here:
Expansion of variables inside single quotes in a command in Bash
(8 answers)
Closed 3 years ago.
I am executing curl command inside bash script.
Issue is in curl command I have to pass some variables($summary,$description).
but as these variables are in single quote('), variables are not getting assigned.
FYI: I can't remove single quote and also can't replace with double quotes.
How can I overcome this situation.
Curl Command:
curl -X POST -d '{"summary": "$summary", "description": "$description", "moduleMapAssets": [{"name":"Rates | IRD"},{"name":"CRD | CRD"}]}' -H "Content-Type: application/json"
You can (and must) use double-quotes, you just need to escape the double-quotes that are part of the string:
curl -X POST -d "{\"summary\": \"$summary\", \"description\": \"$description\", \"moduleMapAssets\": [{\"name\":\"Rates | IRD\"},{\"name\":\"CRD | CRD\"}]}" -H "Content-Type: application/json"
As #MikeHolt pointed out in a comment, it's also possible to mix quoting styles within a single string, so you could switch back and forth between single-quoted sections that include literal double-quotes, and double-quoted sections that include variable references:
curl -X POST -d '{"summary": "'"$summary"'", "description": "'"$description"'", "moduleMapAssets": [{"name":"Rates | IRD"},{"name":"CRD | CRD"}]}' -H "Content-Type: application/json"
To explain that in a little more detail: ... '{"summary": "'"$summary"'", "description"...' is parsed as the single-quoted section '{"summary": "' (within which the double-quotes are literal), followed immediately by the double-quoted section "$summary" (within which the variable gets expanded), followed immediately by another single-quoted section '", "description"...' etc. Since there are no spaces between these sections, they're treated as one long argument to curl.
BTW, if any of your variables can contain double-quotes or backslashes themselves, things get much more complicated. If something like this is a possibility, you should be using something like jq to create the string. Something like this:
jsonstring=$(jq -n --arg summary "$summary" --arg description "$description" '{
summary: $summary,
description: $description,
moduleMapAssets: [{name: "Rates | IRD"}, {name: "CRD | CRD"}]
}' )
curl -X POST -d "$jsonstring" -H "Content-Type: application/json"
try use with backslash on sigle-quotes
curl -X POST -d \'{"summary": "$summary", "description": "$description", "moduleMapAssets": [{"name":"Rates | IRD"},{"name":"CRD | CRD"}]}\' -H "Content-Type: application/json"

Passing Bash Variable to CURL

when i give the values like this it works :
curl --silent \ --insecure \ -X POST \ -d '{"Name" : "Vikram"}' \ -H "Content-Type: application/json" \ $restUrl
but when i give it like this :
post="'{\"Name\" : \"Vikram\"}'"
echo $post // Prints '{"Name" : "Vikram"}'
echo ${post} // Prints '{"Name" : "Vikram"}'
but the following does not work and throws an 400 error:
curl --silent \ --insecure \ -X POST \ -d ${post} \ -H "Content-Type: application/json" \ $restUrl
It seems there are multiple issues.
1) To address the question asked by your title, when you use $post as an argument, the white space in its value causes it to be treated as multiple arguments by Bash. Try putting quotes around it so that it's treated as one argument.
2) I'm guessing you added single quotes to $post, in an attempt to have Bash treat it as a single parameter. Try removing the single quotes.
3) For me at least, all of the backslashes in the curl command were causing it to fail. Maybe you had it split across multiple lines and the copy/paste didn't translate that. I've removed them in my example below.
Putting all together:
post="{\"Name\" : \"Vikram\"}"
curl --silent --insecure -X POST -d "${post}" -H "Content-Type: application/json" $restUrl
Don't put single quotes inside the $post variable, put them around the value to quote it. Then you don't need to escape the double quotes inside the value.
post='{"Name" : "Vikram"}'
Then quote the variable when you use it in the curl command line, to prevent it from being split into multiple arguments.
You also shouldn't have all those backslashes in the curl command line. They're escaping the space after them, so they'll be treated as literal arguments rather than delimiters. The usual time to use backslash in a command is if you're splitting it across multiple lines, then you need to escape the newline so it doesn't end the command.
curl --silent --insecure -X POST -d "${post}" -H "Content-Type: application/json" "$restUrl"
You want to quote ${post}: "${post}", so that your shell does not split the content of your variable.

Variable expansion inside single quotes

I am quite new to shell scripting.
I have the following script:
out="FAILURE"
curl -X POST -d 'json={"json":"message"}' http://localhost:8888/json.tail.test
I want to replace "message" with the $out's value. I tried different ways but could not get that done. Can someone please suggest me?
Do this:
out="FAILURE"
curl -X POST -d 'json={"json":"'$out'"}' http://localhost:8888/json.tail.test
Basically, enclose everything except $out inside single quotes. Single quotes protect double quotes but suppress the expansion of variables like $out.
Try this:
out="FAILURE" curl -X POST -d 'json={"json": $OUT}' http://localhost:8888/json.tail.test
You just need to literally replace "message" with $OUT

variable in bash not working [duplicate]

This question already has answers here:
How do I use variables in single quoted strings?
(8 answers)
Closed 6 years ago.
I have a simple function in my bashrc file, it takes 2 arguments and makes a curl call. The problem is, the curl request is not getting the variable. Here's the function...
checkUserName() {
cd ~/
echo "checking for username $2"
curl -w "#curl-format.txt" -H "Content-Type: application/json" -X POST -d '{"userName": "$2"}' http://localhost:8080/$1/verify
}
alias unameCheck=checkUserName
Then I call it with something like...
unameCheck users danwguy
and I will see...
checking for username danwguy
in my terminal prompt, however when I look at my logs from my application it shows that it is checking for userName $2
So the variable isn't being replaced in the curl command, even though the $1 is being replaced, since it is calling the correct API on my localhost.
It replaces it in the echo command, but not in the curl command.
I have even tried creating a local variable, but that still doesn't work, no matter what I do, it doesn't replace in the curl call, but it does in the echo call.
Can anyone see why it wouldn't be properly replacing the $2
Parameter expansions ($var) will not expand in single quotes. Use double quotes instead:
$ curl -w "#curl-format.txt" \
-H "Content-Type: application/json" \
-X POST \
-d '{"userName": "'"$2"'"}' \
"http://localhost:8080/$1/verify"
Also wrap parameter expansions in double quotes to avoid word splitting and
pathname expansion.
Just a note to previous comment.
You can escape double quotes with backslash, to tell bash interpreter to not interpret its special meaning, so final code looks like:
... -d "{\"userName\": \"$2\"}" ...
Which is way more obvious for me...

How can I use a variable in curl call within bash script [duplicate]

This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 2 months ago.
I have this simple task and I've spent a few hours already trying to figure out how can I use a variable inside a curl call within my bash script:
message="Hello there"
curl -X POST -H 'Content-type: application/json' --data '{"text": "${message}"}'
This is outputting ${message}, literally because it's inside a single quote. If I change the quotes and put double outside and single inside, it says command not found: Hello and then command not found: there.
How can I make this work?
Variables are not expanded within single-quotes. Rewrite using double-quotes:
curl -X POST -H 'Content-type: application/json' --data "{\"text\": \"${message}\"}"
Just remember that double-quotes within double-quotes have to be escaped.
Another variation could be:
curl -X POST -H 'Content-type: application/json' --data '{"text": "'"${message}"'"}'
This one breaks out of the single quotes, encloses ${message} within double-quotes to prevent word splitting, and then finishes with another single-quoted string. That is:
... '{"text": "'"${message}"'"}'
^^^^^^^^^^^^
single-quoted string
... '{"text": "'"${message}"'"}'
^^^^^^^^^^^^
double-quoted string
... '{"text": "'"${message}"'"}'
^^^^
single-quoted string
However, as the other answer and #Charles Duffy pointed out in a comment, this is not a robust solution, because literal " and other characters in $message may break the JSON.
Use the other solution, which passes the content of $message to jq in a safe way, and jq takes care of correct escaping.
While the other post (and shellcheck) correctly points out that single quotes prevent variable expansion, the robust solution is to use a JSON tool like jq:
message="Hello there"
curl -X POST -H 'Content-type: application/json' \
--data "$(jq -n --arg var "$message" '.text = $var')"
This works correctly even when $message contains quotes and backslashes, while just injecting it in a JSON string can cause data corruption, invalid JSON or security issues.

Resources