Bash jq with dynamic name - json

I'm trying to create a script to read the return code from a json from a curl command.
my curl command is:
curl -sk 'https://192.168.0.1/custom/getData.php?device=mydevice&object=http--HTTP_v6_Global Index&indicator=http_httpCode&plugin=xxx' | jq '.'
The json output is:
{
"device": "mydevice",
"object": "http--HTTP_v6_Global ",
"object_descr": "HTTP download of http://192.168.0.1",
"indicator": "http_httpCode",
"indicator_descr": null,
"plugin": "xxx",
"starttime": 1650468121,
"endtime": 1650468421,
"data": {
"1650468248": {
"http_httpCode#HTTP Code": 200
}
}
}
How can read the value "http_httpCode#HTTP Code" if 1650468248 is a dynamic value?

You could use to_entries so you can use .value to target the 'unknown' key:
jq '.data | to_entries | first | .value."http_httpCode#HTTP Code"'
Online demo
Another approach by just 'looping over everything' either with .. or .[]:
jq '.data | .. | ."http_httpCode#HTTP Code"? // empty'
Online demo
jq '.data | .[]."http_httpCode#HTTP Code"'
Online demo
They all return 200

Thanks I solved.
This is my solution:
jq -r '.data | .[]."http_httpCode#HTTP Code"'

Related

Index string array by prefix in JQ

I'm trying to figure out how to print name of keys and specific sub-sub values from it.
My JSON is:
{
"results": 3,
"rows": [
{
"hostname1": {
"tags": [
"owner:TEAM_A",
"friendlyname:myhost1",
"x:abc",
"y:jkl"
]
}
},
{
"hostname2": {
"tags": [
"friendlyname:myhost2",
"owner:TEAM_A",
"x:def",
"q:jkl"
]
}
},
{
"hostname3": {
"tags": [
"owner:TEAM_A",
"x:ghi",
"friendlyname:myhost3",
"q:jkl"
]
}
}
]
}
What I've already achieved is to print just keys of hostnames:
jq -r '.rows[] | keys[]' example.json
hostname1
hostname2
hostname3
I know how to print key:values from tags array:
jq -r .rows[0].hostname1.tags[0,1] example.json
owner:TEAM_A
friendlyname:myhost1
But I can't figure out how to print
hostname1
"owner:TEAM_A",
"friendlyname:myhost1",
hostname2
"owner:TEAM_A",
"friendlyname:myhost2",
hostname3
"owner:TEAM_A",
"friendlyname:myhost3",
Be aware, that the keys in tags array has different order, so I cannot reach it through .rows[0].hostname1.tags[0,1] I'm looking for something like .rows[0].all_keys.tags[owner,friendlyname]
My bash script was very close, but the order of keys brokes it.
hostnames=`jq -r '.rows[] | keys[]' example.json`
count=0
for i in $hostnames
do
jq -r .rows[$count].$i\.tags[0,1] example.json
echo $i
((count=count+1))
done
Turning tags into an object first would make it easier to retrieve tags in a particular order.
.rows[][].tags | INDEX(sub(":.*"; "")) | .owner, .friendlyname
Online demo
And it seems like you don't need a shell loop for this task, JQ can do all that and even more on its own.
.rows[]
| keys_unsorted[] as $hostname
| .[$hostname].tags
| INDEX(sub(":.*"; ""))
| $hostname, "\t" + (.owner, .friendlyname)
Online demo
You can use to_entries to convert an object into an array of key-value pairs, then access .key and .value of its items to your own likings. For instance:
jq -r '.rows[] | to_entries[] | [.key, .value.tags[0,1]] | join("\n ")'
hostname1
owner:TEAM_A
friendlyname:myhost1
hostname2
friendlyname:myhost2
owner:TEAM_A
hostname3
owner:TEAM_A
x:ghi
Demo
Another example:
jq -r '
.rows[] | to_entries[] | [.key, (
.value.tags[] | select(startswith("owner:", "friendlyname:"))
)] | join("\n ")
'
hostname1
owner:TEAM_A
friendlyname:myhost1
hostname2
friendlyname:myhost2
owner:TEAM_A
hostname3
owner:TEAM_A
friendlyname:myhost3
Demo

Cant parse RAW DATA with JQ

I want to create a JSON from the list of servers that are stored inside a variable but I get a parse error.
How can I make this work? I think quoting each server might work but I can't do that since the data is retrieved from a CSV using curl.
server_list=$(curl http://localhost/api/server_list.csv | cut -d ',' -f2);
echo $server_list
host001 host002 host003 host004
echo $server_list | jq '.'
parse error: Invalid numeric literal at line 1, column 15
if that had worked then I could run the following command to create json.
echo $server_list | jq -r '.' | jq -s '{hosts:map({"hostid":.})}')
One invocation of jq is sufficient:
jq -R 'split(" ") | {hosts:map({"hostid":.})}' <<< "$server_list"
Figured it out.
echo $server_list | jq -R 'split (" ")' | jq '.[]' | jq -s '{hosts:map({"hostid":.})}'
If you use echo $server_list | jq -R '.' | jq -s '{hosts:map({"hostid":.})}' will produce:
{
"hosts": [
{
"hostid": "host001 host002 host003 host004"
}
]
}
Not sure if that is exactly what you are expecting for output, but hopefully helps.
With a little bit of additional manipulation within jq you can easily expand the output result.
echo $server_list | jq -s -R '{hosts:split(" ")|map(split("\n"))|map({"hostid": .[0]})}'
{
"hosts": [
{
"hostid": "host001"
},
{
"hostid": "host002"
},
{
"hostid": "host003"
},
{
"hostid": "host004"
}
]
}

How to print path and key values of JSON file using JQ

I would like to print each path and value of a json file with included key values line by line. I would like the output to be comma delimited or at least very easy to cut and sort using Linux command line tools. Given the following json and jq, I have been given jq code which seems to do this for the test JSON, but I am not sure it works in all cases or is the proper approach.
Is there a function in jq which does this automatically? If not, is there a "most concise best way" to do it?
My wish would be something like:
$ cat short.json | jq -doit '.'
Reservations,0,Instances,0,ImageId,ami-a
Reservations,0,Instances,0,InstanceId,i-a
Reservations,0,Instances,0,InstanceType,t2.micro
Reservations,0,Instances,0,KeyName,ubuntu
Test JSON:
$ cat short.json | jq '.'
{
"Reservations": [
{
"Groups": [],
"Instances": [
{
"ImageId": "ami-a",
"InstanceId": "i-a",
"InstanceType": "t2.micro",
"KeyName": "ubuntu"
}
]
}
]
}
Code Recommended:
https://unix.stackexchange.com/questions/561460/how-to-print-path-and-key-values-of-json-file
Supporting:
https://unix.stackexchange.com/questions/515573/convert-json-file-to-a-key-path-with-the-resulting-value-at-the-end-of-each-k
JQ Code Too long and complicated!
jq -r '
paths(scalars) as $p
| [ ( [ $p[] | tostring ] | join(".") )
, ( getpath($p) | tojson )
]
| join(": ")
' short.json
Result:
Reservations.0.Instances.0.ImageId: "ami-a"
Reservations.0.Instances.0.InstanceId: "i-a"
Reservations.0.Instances.0.InstanceType: "t2.micro"
Reservations.0.Instances.0.KeyName: "ubuntu"
A simple jq query to achieve the requested format:
paths(scalars) as $p
| $p + [getpath($p)]
| join(",")
If your jq is ancient and you cannot upgrade, insert | map(tostring) before the last line above.
Output with the -r option
Reservations,0,Instances,0,ImageId,ami-a
Reservations,0,Instances,0,InstanceId,i-a
Reservations,0,Instances,0,InstanceType,t2.micro
Reservations,0,Instances,0,KeyName,ubuntu
Caveat
If a key or atomic value contains "," then of course using a comma may be inadvisable. For this reason, it might be preferable to use a character such as TAB that cannot appear in a JSON key or atomic value. Consider therefore using #tsv:
paths(scalars) as $p
| $p + [getpath($p)]
| #tsv
(The comment above about ancient versions of jq applies here too.)
Read it as a stream.
$ jq --stream -r 'select(.[1]|scalars!=null) | "\(.[0]|join(".")): \(.[1]|tojson)"' short.json
Use -c paths as follows:
cat short.json | jq -c paths | tr -d '[' | tr -d ']'
I am using jq-1.5-1-a5b5cbe

How to loop a json keys result from bash script

input.json:-
{
"menu": {
"id": "file",
"value": "File",
"user": {
"address": "USA",
"email": "user#gmail.com"
}
}
}
Command:-
result=$(cat input.json | jq -r '.menu | keys[]')
Result:-
id
value
user
Loop through result:-
for type in "${result[#]}"
do
echo "--$type--"
done
Output:-
--id
value
user--
I want to do process the keys values in a loop. When I do the above, It result as a single string.
How can I do a loop with json keys result in bash script?
The canonical way :
file='input.json'
cat "$file" | jq -r '.menu | keys[]' |
while IFS= read -r value; do
echo "$value"
done
bash faq #1
But you seems to want an array, so the syntax is (missing parentheses) :
file='input.json'
result=( $(cat "$file" | jq -r '.menu | keys[]') )
for type in "${result[#]}"; do
echo "--$type--"
done
Output:
--id--
--value--
--user--
Using bash to just print an object keys from JSON data is redundant.
Jq is able to handle it by itself. Use the following simple jq solution:
jq -r '.menu | keys_unsorted[] | "--"+ . +"--"' input.json
The output:
--id--
--value--
--user--

Parsing nested json with jq

I am parsing a nested json to get specific values from the json response. The json response is as follows:
{
"custom_classes": 2,
"images":
[
{
"classifiers":
[
{
"classes":
[
{
"class": "football",
"score": 0.867376
}
],
"classifier_id": "players_367677167",
"name": "players"
}
],
"image": "1496A400EDC351FD.jpg"
}
],
"images_processed": 1
}
From the class images=>classifiers=>classes:"class" & "score" are the values that I want to save in a csv file. I have found how to save the result in a csv file. But I am unable to parse the images alone. I can get custom_classes and image_processed.
I am using jq-1.5.
The different commands I have tried :
curl "Some address"| jq '.["images"]'
curl "Some address"| jq '.[.images]'
curl "Some address"| jq '.[.images["image"]]'
Most of the times the error is about not being able to index the array images.
Any hints?
I must say, I'm not terribly good at jq, so probably all those array iterations could be shorthanded somehow, but this yields the values you mentioned:
cat foo.json | jq ".[] | .images | .[] | .classifiers | .[] | .classes | .[] | .[]"
If you want the keys, too, just omit that last .[].`
Edit
As #chepner pointed out in the comments, this can indeed be shortened to
cat foo.json | jq ".images[].classifiers[].classes[] | [.class, .score] | #csv "
Depending on the data this filter which uses Recursive Descent: .., objects and has may work:
.. | objects | select(has("class")) | [.class,.score] | #csv
Sample Run (assuming data in data.json)
$ jq -Mr '.. | objects | select(has("class")) | [.class,.score] | #csv' data.json
"football",0.867376
Try it online at jqplay.org
Here is another variation which uses paths and getpath
getpath( paths(has("class")?) ) | [.class,.score] | #csv
Try it online at jqplay.org
jq solution to obtain a prepared csv record:
jq -r '.images[0].classifiers[0].classes[0] | [.class, .score] | #csv' input.json
The output:
"football",0.867376