You can use here-doc:
foo=$(cat <<EOF {"Comment":"Update DNSName.","Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"alex.","Type":"A","AliasTarget":{"HostedZoneId":"######","DNSName":"$bar","EvaluateTargetHealth":false}}}]} EOF )
If you leave EOF in the first line without quotes, the contents of this document will be subject to expansion of parameters, so your $bar will expand to what you place there.
If you can have line breaks in your JSON, you can make it more readable:
foo=$(cat <<EOF { "Comment": "Update DNSName.", "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "alex.", "Type": "A", "AliasTarget": { "HostedZoneId": "######", "DNSName": "$bar", "EvaluateTargetHealth": false } } } ] } EOF )
or even (the first indent on each line should be a tab)
foo=$(cat <<-EOF { "Comment": "Update DNSName.", "Changes": [ { "Action": "UPSERT", "ResourceRecordSet": { "Name": "alex.", "Type": "A", "AliasTarget": { "HostedZoneId": "######", "DNSName": "baz", "EvaluateTargetHealth": false } } } ] } EOF )
and show how it is stored, including quoting (provided that bar=baz ):
$ declare -p foo declare -- foo="{ \"Comment\": \"Update DNSName.\", \"Changes\": [ { \"Action\": \"UPSERT\", \"ResourceRecordSet\": { \"Name\": \"alex.\", \"Type\": \"A\", \"AliasTarget\": { \"HostedZoneId\": \"######\", \"DNSName\": \"baz\", \"EvaluateTargetHealth\": false } } } ] }"
Since this extends the shell metacharacters, you may run into problems if your JSON contains something like * , so you can assign directly, but be careful when quoting $bar :
foo='{"Comment":"Update DNSName.","Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"alex.","Type":"A","AliasTarget":{"HostedZoneId":"######","DNSName":"'"$bar"'","EvaluateTargetHealth":false}}}]}'
Note the quote for $bar : this
"'"$bar"'" βββ βββ βββ βββ literal double quote βββ ββ opening syntactical single quote βββ β closing syntactical double quote βββ opening syntactical double quote ββ closing syntactical single quote β literal double quote