tech-otaku
tech-otaku

Reputation: 91

cURL throwing globbing error when JSON data in variable contains a space

Using bash v4.3.48(1) on Ubuntu 16.04.2 LTS and bash v3.2.57 on macOS Sierra 10.12.5 I have this code which POSTs JSON data stored in a variable:

#1    
JSON_DATA="Test"; \
curl -X POST "https://www.techotaku.com/json.php" \
    -H "Content-Type: application/json" \
    -d '{"data":"'$JSON_DATA'"}'

This returns:

Array
(
    [data] => Test
)

However, if $JSON_DATA contains a space...

#2
JSON_DATA="A Test"; \
curl -X POST "https://www.techotaku.com/json.php" \
    -H "Content-Type: application/json" \
    -d '{"data":"'$JSON_DATA'"}'

...it throws an error:

curl: (3) [globbing] unmatched close brace/bracket in column 6

I thought this might be due to incorrect use of quotes, but if I echo the JSON data...

echo '{"data":"'$JSON_DATA'"}'

...it appears well-formed:

{"data":"A Test"}

Also, if I include the JSON data as a string and not a variable, it works.

#3
curl -X POST "https://www.techotaku.com/json.php" \
    -H "Content-Type: application/json" \
    -d '{"data":"A Test"}'

The only way I can get it to work if the variable contains a space is to enclose the JSON data in double-quotes and escape the literal double-quotes in the string:

#4    
JSON_DATA="A Test"; \
curl -X POST "https://www.techotaku.com/json.php" \
    -H "Content-Type: application/json" \
    -d "{\"data\":\"$JSON_DATA\"}"

I would have thought that all 4 examples would have worked. So, can anyone throw any light on why only examples 1,3 and 4 work and example 2 doesn't?

Many thanks, Steve.

Upvotes: 2

Views: 4836

Answers (1)

randomir
randomir

Reputation: 18687

You should quote your variables to prevent word splitting by shell. Your second example:

'{"data":"'$JSON_DATA'"}'

doesn't work because it's being expanded by bash to two words:

{"data":"A Test"}

so -d option receives 2 arguments ({"data":"A and Test"}). If JSON_DATA contained globbing metacharacters, those would cause filename expansion.

To fix it, quote it:

'{"data":"'"$JSON_DATA"'"}'

Note the use of alternating single and double quotes. This will be expanded to a single word:

{"data":"A Test"}

Here's a more detailed answer I wrote some time ago which also mentions another convenient option, the use of a here-document.

Upvotes: 6

Related Questions