Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Store JSON directly in bash script with variables?

Tags:

json

bash

I'm going to preface by saying that "no, find a different way to do it" is an acceptable answer here.

Is there a reliable way to store a short bit of JSON in a bash variable for use in a AWS CLI command running from the same script?

I'll be running a job from Jenkins that's updating an AWS Route53 record, which requires UPSERTing a JSON file with the change in records. Because it's running from Jenkins, there's no local storage where I can keep this file, and I'd really like to avoid needing to do a git checkout every time this project will run (which will be once an hour).

Ideally, storing the data in a variable ($foo) and calling it as part of the change-resource-record-sets command would be most convenient given the Jenkins setup, but I'm unfamiliar with exactly how to quote/store JSON inside bash - can it be done safely?

The specific JSON in this case is the following;

{"Comment":"Update DNSName.","Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"alex.","Type":"A","AliasTarget":{"HostedZoneId":"######","DNSName":"$bar","EvaluateTargetHealth":false}}}]} 

As an added complication the DNSName value - $bar - needs to be expanded.

like image 893
Alex Avatar asked Apr 12 '17 15:04

Alex


People also ask

Can you use variables in JSON?

Variables provide a new way to tackle different scenarios where JSON schema alone fails. This means, that you can use a new keyword named $vars to make your life easier.

What is $@ in bash script?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.

Can bash handle JSON?

Unfortunately, shells such as Bash can't interpret and work with JSON directly. This means that working with JSON via the command line can be cumbersome, involving text manipulation using a combination of tools such as sed and grep.


1 Answers

You could use a here-doc:

foo=$(cat <<EOF {"Comment":"Update DNSName.","Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"alex.","Type":"A","AliasTarget":{"HostedZoneId":"######","DNSName":"$bar","EvaluateTargetHealth":false}}}]} EOF ) 

By leaving EOF in the first line unquoted, the contents of the here-doc will be subject to parameter expansion, so your $bar expands to whatever you put in there.

If you can have linebreaks in your JSON, you can make it a little 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 (first indent on each line must be a tab)

foo=$(cat <<-EOF     {       "Comment": "Update DNSName.",       "Changes": [         {           "Action": "UPSERT",           "ResourceRecordSet": {             "Name": "alex.",             "Type": "A",             "AliasTarget": {               "HostedZoneId": "######",               "DNSName": "$bar",               "EvaluateTargetHealth": false             }           }         }       ]     }     EOF ) 

and to show how that is stored, including quoting (assuming 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         }       }     }   ] }" 

Because this expands some shell metacharacters, you could run into trouble if your JSON contains something like `, so alternatively, you could assign directly, but be careful about quoting around $bar:

foo='{"Comment":"Update DNSName.","Changes":[{"Action":"UPSERT","ResourceRecordSet":{"Name":"alex.","Type":"A","AliasTarget":{"HostedZoneId":"######","DNSName":"'"$bar"'","EvaluateTargetHealth":false}}}]}' 

Notice the quoting for $bar: it's

"'"$bar"'" │││    │││ │││    ││└ literal double quote │││    │└ opening syntactical single quote │││    └ closing syntactical double quote ││└ opening syntactical double quote │└ closing syntactical single quote └ literal double quote 
like image 157
Benjamin W. Avatar answered Sep 20 '22 19:09

Benjamin W.