I'm trying to create a JSON in BASH where one of the fields is based on the result of an earlier command

BIN=$(cat next_entry)
echo $OUTDIR
JSON="'"'{"hostname": "localhost", "outdir": "${OUTDIR}", "port": 20400, "size": 100000}'"'"
echo $JSON

The above script when executed, returns:

, port: 20400, size: 100000}': /tmp/cpupower/0

How can I properly substitute variables inside these multi-quoted strings?

  • 1
    I think I just saw a hookah-smoking caterpillar and a grinning cat. (1) I don’t see any way that the commands presented in the question could have produced the output presented in the question.  (Note that the OUTDIR variable appears to be expanded in the value of JSON, and the quotes around "port" and "size" are inexplicably absent.)  (2) It seems obvious to me that the BIN variable is getting a carriage return in it (from the next_entry file); and yet the problem apparently went away without that issue being addressed. – G-Man Says 'Reinstate Monica' May 25 '19 at 6:53
JSON=\''{"hostname": "localhost", "outdir": "'"$OUTDIR"'", "port": 20400, "size": 100000}'\'

That is get out of the single quotes for the expansion of $OUTDIR. We did put that expansion inside double-quotes for good measure even though for a scalar variable assignment it's not strictly necessary.

When you're passing the $JSON variable to echo, quotes are necessary though to disable the split+glob operator. It's also best to avoid echo for arbitrary data:

printf '%s\n' "$JSON"
| improve this answer | |
  • Cool. This works! Could you perhaps explain a little more on why this works? What is the significance of the first \'. I don't believe I've seen that on some of the examples I've seen on SO/unix.stackexchange. – Guru Prasad Sep 27 '16 at 14:29
  • Backslash before ' tells the shell to treat ' as any ordinary character, instead of interpreting it as a string delimiter. The backslash can be used in front of a few other characters. For example, \\ will represent the \ character itself and \" means the " character literary. See for example the \n in above printf argument, where printf interprets \n as the line-feed character. – Rein Sep 30 '16 at 16:47
  • 1
    (1) I believe that you should have been clearer that the change from "'" to \' was a totally stylistic (i.e., arbitrary) one, and that the only substantive change you made was the quotes around $OUTDIR. (You might also have mentioned that the braces in ${OUTDIR} simply were not necessary.)  (2) Please see my comment on the question and tell me whether I’m hallucinating (i.e., did I overlook something, or did you?). – G-Man Says 'Reinstate Monica' May 25 '19 at 6:53
  • @G-Man, I agree with you. – Stéphane Chazelas May 25 '19 at 7:03

Stéphane's answer is great, and upvoted. Here's just a tip; instead of doing

BIN=$(cat next_entry)

You can do:


And thus save spawning an extra process. Read more here.

| improve this answer | |

If you ended up here trying to use AWS commands, @Stéphane Chazelas's answer almost works. In here, the initial escaped quotes (\') are not necessary, they actualy break the command.

IP=$(curl ipecho.net/plain ; echo)

aws ec2 authorize-security-group-ingress --group-id sg-**************** \
    --ip-permissions '[{"IpProtocol": "tcp", "FromPort": 15000, "ToPort": 15000, "IpRanges": [{"CidrIp": "'"$IP/32"'", "Description": "Service A"}]}]'

^ This works just fine

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.