I have the following input:
[
{"id": "first", "val": 1},
{"id": "second", "val": 2},
{"id": "second", "val": 3}
]
Using the jq filter : .[] | select(.id == "second")
I get following as output :
{
"id": "second",
"val": 2
}
{
"id": "second",
"val": 3
}
I want to get the result in the form of an array. Is it possible to get the multiple result values of select operation in an array?
Yes; wrap the filter in an array :)
$ jq '[.[] | select(.id == "second")]' tmp.json
[
{
"id": "second",
"val": 2
},
{
"id": "second",
"val": 3
}
]
Or, use map/1, which is predefined as [.[] | ...].
$ jq 'map(select(.id == "second"))' tmp.json
[same result]
To wrap the results in a bash array, use the -c option to output each result on a single line, and read the result with readarray.
$ readarray -t arr < <(jq -c '.[] | select(.id == "second")' tmp.json)
$ for r in "${arr[#]}"; do echo "Result: $r"; done
Result: {"id":"second","val":2}
Result: {"id":"second","val":3}
Related
Let's assume $commandGetEvents is an array of json objects. I use the following command to extract the event Id, which is a number from 1 - 65 and store it in currentEventId. Now let's assume I have another variable called startedEventId which holds the value I'm looking for, which is 22.
Here's an example of the data $commandGetEvents contains.
[
{
"eventId": 22,
"Name" : "Bob"
"Activity" : "Eat Food"
"startedEventId" : 15
},
{
"eventId": 21,
"Name" : "Smith"
"Activity" : "Ride a bike"
"startedEventId" : 13
},
{
"eventId": 20,
"Name" : "Tony"
"Activity": "Print paper"
"startedEventId" : 10
},
]
eventId is the unique identifier of the json object. & startedEventId is the identifier of json object that caused the current one to take place.
currentEventId=$(jq ".[$index].eventId" <<< ${commandGetEvents})
startedEventid=$(jq ".[${eventCounter}].startedEventId" <<< $commandGetEvents)
When i echo both statements in a while loop, I get the following output.
currentEventId = 1
startedEventId = 22
currentEventId = 2
startedEventId = 22
currentEventId = 3
startedEventId = 22
The while loop continues until all elements of currentEventId are exhausted.
My problem is when I compare both statements like this:
if [[ ${startedId} -eq ${currentEventId} ]] ;
then
echo "Equal"
fi
I get the following error message:
line 90: [[: 22: syntax error: operand expected (error token is "22")
The provided "JSON" is invalid as JSON. Please fix it.
When using jq at the bash command line, it's almost always best to enclose the jq program in single-quotation marks; bash shell variables can be passed in using --arg or --argjson. Consider for example the following snippet that assume `commandGetEvents' is valid JSON along the lines suggested in the Q:
index=0
currentEventId=$(jq --argjson index $index '.[$index].eventId' <<< ${commandGetEvents})
echo index=$index
echo currentEventId=$currentEventId
The part of the question involving eventCounter is somewhat obscure, but it looks like the example given immediately above will serve as a guide.
Rather than using bash constructs to iterate through the JSON array, it would almost certainly be better to use jq's support for iteration and selection. For example:
jq '.[] | select(.eventId == 22)' <<< ${commandGetEvents}
yields:
{
"eventId": 22,
"Name": "Bob",
"Activity": "Eat Food",
"startedEventId": 15
}
So if you just want the startedEventId value (or values) corresponding to .eventId == 22, you could write:
jq '.[] | select(.eventId == 22) | .startedEventId' <<< ${commandGetEvents}
I have a string in this format:
string= "[one,two,three,four,five]"
I want to convert it to json format likely, without using any specific tool (jq or other) , I want to do it with pure shell:
[
{"id" : 0 , "word": "one"} ,
{"id" : 1 , "word": "two"} ,
{"id" : 2 , "word": "three"} ,
{"id" : 3 , "word": "four"} ,
{"id" : 4 , "word": "five"}
]
Suggestions ?
There is no legitimate reason not to use tr or jq for this. Portably, you cannot use read -d as below, but this is so absurdly fragile that it's not worth worrying about portability. This works in bash:
$ string="[one,two,three,four,five]"
$ c=0; echo '['; while read -d , i; do
echo "{\"id\" : $((c++)), \"word\": \"${i%]}\"},"
done <<< "${string#[}",; echo ']';
[
{"id" : 0 , "word": "one"},
{"id" : 1 , "word": "two"},
{"id" : 2 , "word": "three"},
{"id" : 3 , "word": "four"},
{"id" : 4 , "word": "five"},
]
At the moment, I can't think of a clean way to eliminate the trailing comma without tr (although I suppose you could use the rather banal if test "$c" -eq 5; then ...., but that's boring) so I'll just propose:
c=0; echo '['; while read -d , i; do
printf "{\"id\" : $((c++)), \"word\": \"${i%]}\"}";
expr $c = 5 | tr 10 ' ,'; done <<< "${string#[}",; echo ']'
I'll reiterate that this is absurdly fragile and only has value as an exercise. Use jq.
This may be still tedious but how about:
string="[one,two,three,four,five]"
out=$(while read -r -d, i; do
printf '{"id" : %d , "word": "%s"},\n' "$((c++))" "${i%]}"
done <<< "${string#[},")
printf "[\n%s\n]\n" "${out%,}"
Output:
[
{"id" : 0 , "word": "one"},
{"id" : 1 , "word": "two"},
{"id" : 2 , "word": "three"},
{"id" : 3 , "word": "four"},
{"id" : 4 , "word": "five"}
]
I have a json with 3 equal lists:
{
"value": {
"list1": [
"el11",
"el12",
"el13",
"el14"
],
"list2": [
"el21",
"el22",
"el23",
"el24"
],
"list3": [
"el31",
"el32",
"el33",
"el34"
]
}
}
I'm trying to extract from each list the elements with the same index:
el11 el21 el31
...
el13 el23 el33
Ideally those need to be exported as ENV values. But I just want to know if it's possible to do that with jq. And how.
Thank you
You can use the transpose function for this. For example,
$ jq -r '[.value[]] | transpose[] | join (" ")' tmp.json
el11 el21 el31
el12 el22 el32
el13 el23 el33
el14 el24 el34
I have the following line:
for custom_field in $(jq -r '.issues[] | .fields.created' 1.json
); do
echo $custom_field
done
Output:
2018-03-06T21:24:41.000+0000
2018-03-06T22:48:47.000+0000
How to compare current datetime with each output and if it's older than 3 hours to print "old"?
Given input like
{ "issues":
[{"id": 1, "fields": {"created": "2018-03-06T21:24:41.000+0000"}},
{"id": 2, "fields": {"created": "2018-03-06T22:48:47.000+0000"}},
{"id": 3, "fields": {"created": "2018-03-09T22:48:47.000+0000"}}]}
you can use the built-in date manipulation functions to print the old records with something like
jq -r '(now-3600*3) as $when | .issues[] |
select(.fields.created | strptime("%Y-%m-%dT%H:%M:%S.000+0000") | mktime < $when) |
[.id, .fields.created, "old"]' 1.json
where the last line probably needs tweaking to produce exactly the output you want.
It is much easier to convert first and subtract the three hours.
Example below converts to seconds and prints true if condition is met.
date_in_seconds=$(date -d $custom_field +"%s");
[ ${date_in_seconds} -gt 259200 ] && echo true;
For non GNU versions of the date command you can use the following;
date_in_seconds=$(date -j -f '%Y-%m-%d %H:%M:%S' "2016-02-22 20:22:14" '+%s')
Keep in mind that the EPOCH will rollover 1 Jan 2036.
I have a text file following a certain formatting which has lines like :
{
"297723": [
[
1,
2
],
[
5,
10
],
[
1,
157
]
],
"369258": [
[
3,
4
],
[
6,
11
],
[
30,
200
]
]
}
How can I make it look like this ?
{"297723": [[1, 2], [5, 10], [1,157]],
{"369258": [[3, 4], [6, 11], [30,200]]}
Of course, there are several blocks, I just append the first (which starts with "{" and the last which closes with "}" - in all the rest, there is a number (like "2927723" in my example) which notifies the new block.
Your input is a valid JSON, so you may apply jq tool for this case:
jq -c '.' yourfile | sed 's/,"/,\n"/'
The output:
{"297723":[[1,2],[5,10],[1,157]],
"369258":[[3,4],[6,11],[30,200]]}
-c - print the input in compact-output form