3

I have a variable with nested json,

a={
  "version": "3.0",
  "user": "unknown_unknown",
  "dateGenerated": "2020-07-08T11:53:23Z",
  "status": "OK",
  "data": [
    {
      "parameter": "t_2m:C",
      "coordinates": [
        {
          "lat": 39.23054,
          "lon": 9.11917,
          "dates": [
            {
              "date": "2020-07-08T15:53:23Z",
              "value": 25.1
            }
          ]
        }
      ]
    }
  ]
}

Looking for a way to grep the "value" in the nested json (like the one highlighted) in variable a.

I'am using grep and jq but I can't show value, it shows "dates" (echo $result | grep -Po '"dates":.*?[^\\],.*?[^\\]"') but not just the value.

Any help?

1
  • Will there always be just one value? What operating system are you using? Do you have the GNU tools? Does your grep support -o? And, of so, would something as simple as grep -oP '(?<=value":)[0-9.]+' <<<"$a" do?
    – terdon
    Jul 8, 2020 at 12:31

3 Answers 3

11

You want the "value" from (the first object in the "dates" array) from (the first object in the "coordinates" array) from (the first object in the "data" array)

$ a='{"version":"3.0","user":"unknown_unknown","dateGenerated":"2020-07-08T11:53:23Z","status":"OK","data":[{"parameter":"t_2m:C","coordinates":[{"lat":39.23054,"lon":9.11917,"dates":[{"date":"2020-07-08T15:53:23Z","value":25.1}]}]}]}'
$ echo "$a" | jq -r '.data[0].coordinates[0].dates[0].value'
25.1
9

You may also want to consider installing gron, which is a utility to "Make JSON greppable!".

With a defined as in your question,

echo $a | gron

returns

json.data = [];
json.data[0] = {};
json.data[0].coordinates = [];
json.data[0].coordinates[0] = {};
json.data[0].coordinates[0].dates = [];
json.data[0].coordinates[0].dates[0] = {};
json.data[0].coordinates[0].dates[0].date = "2020-07-08T15:53:23Z";
json.data[0].coordinates[0].dates[0].value = 25.1;
json.data[0].coordinates[0].lat = 39.23054;
json.data[0].coordinates[0].lon = 9.11917;
json.data[0].parameter = "t_2m:C";
json.dateGenerated = "2020-07-08T11:53:23Z";
json.status = "OK";
json.user = "unknown_unknown";
json.version = "3.0";

which does indeed make it easy to process:

$ echo $a | gron | sed -n '/value/{s/.* //; s/;//; p;}'
25.1

$ echo $a | gron | awk '/value/ {sub(/;/,""); print $NF;}'
25.1
2
  • thanks for the pointer to gron .. been lookin for something like that
    – rr0ss0rr
    Jul 8, 2020 at 18:13
  • I'm assuming that gron would not decode the string values, which means that if you use this to get an encoded string value, you would have to decode it yourself.
    – Kusalananda
    Mar 25, 2021 at 20:25
5

Using Miller, with its default JSON array flattening:

$ mlr --ijson --onidx cut -f 'data:0:coordinates:0:dates:0:value' <<<"$a"
25.1

or regex-matching the flattened element name

$ mlr --ijson --onidx cut -r -f 'value$' <<<"$a"
25.1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .