Expanding bash variables inside jq
Expanding bash variables inside jq
Expanding variables inside jq
It took me 3.5 hours to figure out the hard way that JQ supports variables in a simple but peculiar way.
I hope it really helps somebody else.
How to do it
Here’s what the data set looks like, btw:
$ gcloud auth list --format=json
[
{
"account": "inger.klekacz@workaccount.com",
"status": ""
},
{
"account": "ingernet@personalaccount.com",
"status": "ACTIVE"
}
]
Now, remember, bash doesn’t expand variables inside single quotes:
$ tmp_authed_user=$(gcloud auth list --format=json | jq -r '.[] | select(.status=="ACTIVE") | .account')
$ echo '$tmp_authed_user'
$tmp_authed_user # boo hiss
$ echo "$tmp_authed_user"
ingernet@personalaccount.com
Hurray but still not enough, yet, because we still have to somehow jam it between two single quotes like jq
likes.
$ jqstring="'.bindings[] | select(.members[] | contains("'"'${tmp_authed_user}'"'")) | .role'" # kill me now
Let’s see if it runs, I guess?
$ echo $jqstring
'.bindings[] | select(.members[] | contains("ingernet@personalaccount.com")) | .role'
I mean, I’ll try it? Hold my beer
$ gcloud projects get-iam-policy my-fancy-project --format=json | jq $jqstring
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
'.bindings[]
wheeeeeeee
Well, dear reader, listen close: I was definitely overthinking things. Here’s how you do it:
# unset that ungodly jqstring, ain't nobody got time for that
$ unset jqstring
# set the user variable
$ tmp_authed_user=$(gcloud auth list --format=json | jq -r '.[] | select(.status=="ACTIVE") | .account')
# pass it into the jq command as an argument, making sure to wrap it in quotes first -
# notice that i named the arg "authed_user" to show that it's actually getting used
# inside the scope of jq instead of just being the bash variable
$ gcloud projects get-iam-policy my-fancy-project --format=json | jq --arg authed_user "${tmp_authed_user}" -r '.bindings[] | select(.members[] | contains($authed_user)) | .role'
roles/owner
roles/resourcemanager.projectMover
roles/secretmanager.admin
Easy peasy. Right? Uggh.
Why would you do that?
The most immediate application that comes to mind is if you’re looping through a list of users and want to get the IAM credentials for all of them (since that’s what I was trying to do when I went down this rabbit hole). But I imagine this will be helpful for running a jq query against any list of strings - for x in y
, etc.
Caveats
The code above doesn’t grab ALL of the credentials - only the IAM creds assigned at the GCP project level. As of right now, the gcloud SDK doesn’t pull in creds inherited from folders, which is a drag. But this gist isn’t about that. Anyway, just a heads up.