I’m trying to post data to an API using curl, I’m using this bash script:
script.sh
send_command () {
echo "{\"cmd\":\"$@\"}"
curl --request POST \
--data-raw "{\"cmd\":\"$@\"}" \
-H "Content-Type: application/json"\
"http://localhost:8080/addCmd/"
}
command_1 () {
send_command test_command \
-I {{files1}} \
---files1 'my_file.txt'\
}
after sourcing from script.sh then running command_1 in the terminal, I get this error:
{"cmd":"test_command -I {{files1}} ---files1 my_file.txt"}
curl: option ---files1: is unknown
curl: try 'curl --help' or 'curl --manual' for more information
I changed ---files1 to --files1 and it produces the same error.
>Solution :
"$@" expands to multiple words (see 2.5.2 Special Parameters of the POSIX shell language specification).
Consequently, --data-raw "{\"cmd\":\"$@\"}" expands to more than 2 tokens if you passed multiple parameters to your function. For instance, invoking send_command a 'b c' d will expand to the following tokens:
'--data-raw' '{"cmd":"a' 'b c' 'd"}'
Which means that 'b c' and 'd"}' will be parsed as distinct parameters to curl.
If you want all parameters to expand to a single word, use "$*":
curl --data-raw '{"cmd":"'"$*"'"}'
(or the equivalent --data-raw "{\"cmd\":\"$*\"}", depending on whether you prefer to escape nested quotes.)
But this will still break when one of your parameters contains a double quote, because the result will be invalid JSON.
If you need to generate/construct JSON, I recommend using jq:
jq -nc --arg cmd "$*" '{$cmd}' | curl --data-raw @-
or
curl --data-raw "$(jq -nc --arg cmd "$*" '{$cmd}')"
This does not suffer from the same limitations and will properly escape any embedded quotes in your input.
Or, if you have HTTPie available:
http :8080/addCmd/ cmd="$*"