I'm trying to parse environment variables from the JSON output of docker inspect
. Annoyingly, those environment variables aren't returned as useful key-value pairs. They're just an array of x=y strings. Here's a relevant snippet of the output:
[
{
"Config": {
"Env": [
"JENKINS_HOST=1.2.3.4",
"JENKINS_INSTANCE=tea",
"JENKINS_NAME=Enterprise Architecture Tools",
"JENKINS_VERSION=2.46.2",
"JENKINS_PROTOCOL=http"
]
}
}
]
I would like to convert that array into something like this:
{
"Config": {
"Env": {
"JENKINS_HOST": "1.2.3.4",
"JENKINS_INSTANCE": "tea",
"JENKINS_NAME": "Enterprise Architecture Tools",
"JENKINS_VERSION": "2.46.2",
"JENKINS_PROTOCOL": "http"
}
}
}
That way, I can use a command like jq '.[] | .Config.Env.JENKINS_HOST'
to get the values that I care about. I can't figure out how to accomplish this.
It's relatively easy to select the data and even split the key and value into separate elements. For instance, if I use jq '.[] | .Config.Env | .[] | split("=")'
, I get data like this:
[
"JENKINS_HOST",
"1.2.3.4"
]
[
"JENKINS_INSTANCE",
"tea"
]
[
"JENKINS_NAME",
"Enterprise Architecture Tools"
]
[
"JENKINS_VERSION",
"2.46.2"
]
[
"JENKINS_PROTOCOL",
"http"
]
However, I can't figure out how to turn that data into an object assignment. It seems like it should probably be some combination of map
or reduce
, but I'm stumped. Can anyone point me in the right direction?
To convert an array of two strings (e.g. ["k", "v"]) to an object, you can write:
{ (.[0]) : .[1] }
So you'll want to write something like:
map(.Config.Env |= (map( split("=") | { (.[0]) : .[1] } ) | add))
Abstracting out the array-to-object functionality makes the solution a bit more digestible:
def a2o: map( split("=") | { (.[0]) : .[1] } ) | add;
map(.Config.Env |= a2o)
match
or capture
instead of split
Since it is possible for an "=" character to appear in the "value" part of each var=value
string, using split
naively might not be such a great idea. Here is a more robust alternative, assuming your jq supports regular expressions:
match("([^=]*)=(.*)") | .captures | {(.[0].string) : .[1].string}
Or, slightly more succinctly and perhaps elegantly:
[capture( "(?<key>[^:]*):(?<value>.*)" )] | from_entries
index/1
If your jq does not have regex support, you could use index/1
, along these lines:
index("=") as $ix | {(.[:$ix]) : .[$ix+1:]}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With