JQ Check if Array Contains an Element [duplicate] - jq

This question already has answers here:
How to check if element exists in array with jq
(6 answers)
Closed 1 year ago.
I've looked through many other stack overflow questions that are similar, but can't find exactly what I'm looking for. This seems simple, but I cannot get the syntax quite right and I'm tired of throwing spaghetti at the wall. Given this return from the AWS CLI:
{
"IPSet":{
"Description":"",
"Name":"testip",
"IPAddressVersion":"IPV4",
"Id":"a1b2c3d4-5678-90ab-cdef-EXAMPLE1111",
"ARN":"arn:aws:wafv2:us-west-2:123456789012:regional/ipset/testip/a1b2c3d4-5678-90ab-cdef-EXAMPLE1111",
"Addresses":[
"192.0.2.0/16"
]
},
"LockToken":"447e55ac-2396-4c6d-b9f9-86b67c17f8b5"
}
How would use JQ to determine if it contained a certain IP address? This is my closest guess so far, but not quite right.
echo ${single_ip_set} | jq -c '.IPSet.Addresses[] | contains("255.255.255.8")'
single_ip_set is my variable name. This checks every element in the array and gives a response. So does this:
echo ${single_ip_set} | jq -c '.IPSet.Addresses[] | index("255.255.255.8")'
I really just want one final answer as whether or not the array contains one instance. of my requested IP.

If you want to determine if any value in a sequence is true for a predicate, this is a job for any(). If you want to do an exact string comparison, == is the right tool for that job.
jq -c \
--arg tgt "192.0.2.0/16" \
'.IPSet.Addresses | any(. == $tgt)' \
<<<"$single_ip_set"
...is true, whereas:
jq -c \
--arg tgt "255.255.255.8" \
'.IPSet.Addresses | any(. == $tgt)' \
<<<"$single_ip_set"
...is false.

Related

jq select input based on values in array

I have a list of country codes like FR, IT, DE and have been trying to figure out how to use this in a select statement. I was doing something like
cat stuff | jq -c '.[]| select(.country_iso3166_alpha2 == "US")'
But then my list grew to a large number of countries I want to match on. So I tried using IN since I'm using jq 1.6 and did something like this:
eu=("FR", "IT"); cat stuff | jq -c '.[]| select(.country_iso3166_alpha2 IN($eu)'
I've been reading the docs and looking at the cookbook but it's not making any sense to me. Thanks!
You can use --argjson to pass the list to jq and IN to select the matching entries.
jq -c --argjson eu '["FR", "IT"]' '.[]| select(.country_iso3166_alpha2 | IN($eu[]))' <stuff
Broken out to show the individual parts:
jq -c \
--argjson eu '["FR", "IT"]' \
'.[]| select(.country_iso3166_alpha2 | IN($eu[]))' \
<stuff
invoke jq with compact output
pass in the list of countries as a json array named "eu"
select using the IN operator, unpacking $eu[] to get its values
redirect the input file into jq
Unfortunately, jq does not understand bash arrays.
Things would probably be simplest if you can arrange to have your shell variable be a string representing a JSON array:
eu='["FR", "IT"]'
jq -n --argjson eu "$eu" '$eu'
Or if you prefer:
eu='["FR", "IT"]' jq -n 'env.eu | fromjson'
Another possibility would be to write your bash array into a file, and then slurp the file.
There are also many variants of the above....

How can I summarize a property across multiple files with jq?

I have a number of JSON files that look like this:
{
"property": "value1",
...
}
What I want is an output file that looks like this:
{
"<filename1>": "<value1>",
"<filename2>": "<value2>",
"<filename3>": "<value3>",
...
}
This can be achieved with two jq invocations and a shell pipe:
jq '{(input_filename):.property}' * | jq -s add
However, I was wondering whether this is possible with a single jq invocation (or any other simpler way).
I'm currently using jq version 1.5-1 in case it's relevant.
Use inputs in combination with the -n option to sequentially access all input files.
In direct analogy, you could just create the array that would have been created by the -s option using [inputs], and then add up the items as you did before:
jq -n '[inputs | {(input_filename): .property}] | add' *
But in a more straightforward way, you could employ reduce to iteratively build up your result object:
jq -n 'reduce inputs as $in ({}; .[input_filename] = $in.property)' *

How to print results of jq in single row, not pretty formatted [duplicate]

This question already has an answer here:
json format each object in a line
(1 answer)
Closed 2 years ago.
How can jq get convinced to return results in one row?
Without any options, the results get formatted
echo '{"name":"New release","description":"Super nice release","milestones":["v1.0","v1.0-rc"]}' | jq '.milestones'
[
"v1.0",
"v1.0-rc"
]
I would like to have it in one row:
echo '{"name":"New release","description":"Super nice release","milestones":["v1.0","v1.0-rc"]}' | jq '.milestones'
["v1.0","v1.0-rc"]
From the manual
--compact-output / -c:
By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each JSON object on a single line.
can stand in front and behind the filter
echo '{"name":"New release","description":"Super nice release","milestones":["v1.0","v1.0-rc"]}' | jq -c '.milestones'
["v1.0","v1.0-rc"]
echo '{"name":"New release","description":"Super nice release","milestones":["v1.0","v1.0-rc"]}' | jq '.milestones' -c
["v1.0","v1.0-rc"]

Proper syntax for jq while filtering github commit

I am struggling with the proper jq syntax for pulling out all the names from a curl call that looks like this:
my #repo = curl -s -R -D $tmp_fh_header -u $o_user:$o_auth https://api.github.com/repos/mycompany/$repo/commits| jq '.[].login';
In my case, it should report 10 names, but it only comes back with 5 nulls.
Can you point me in the right direction?
If you need the names for the author of the last commits, you can use:
curl -s https://api.github.com/repos/mycompany/$repo/commits | jq '.[].author.login'
If you need the names for the committer of the last commits, you can use:
curl -s https://api.github.com/repos/mycompany/$repo/commits | jq '.[].committer.login'
or if you need the unique names for that last call:
curl -s https://api.github.com/repos/mycompany/$repo/commits | jq '[.[].committer.login] | unique'
You can use pagination for more/less results as documented in https://developer.github.com/v3/#pagination

Is there a better way to pass string output from jq to bash?

I’ve just discovered jq and been really loving it. One thing I find myself doing a lot though stuff like:
result=$(jq --raw-output '.some | .filters // ""')
if [[ $result ]]; then
foo
else
bar
fi
The default to an empty string seems to play more nicely with bash "truthiness" than e.g. if [[ $result != "null" ]], and raw-output is usually necessary to store just the resultant string in a variable. My question is, I’m using these two tweaks so consistently in scripts, is there perhaps a better way to achieve the same functionality? Or would it make sense (as a possible enhancement to jq) to be able to set a couple env vars to control this behavior for the duration of the script?
You can use the -e flag that will make jq return exit code 0 if the last output value was neither false or null so then your logic may become:
result=$(jq -e -r '.some | .filters') && foo || bar

Resources