11

I have a JSON output that contains a list of objects stored in a variable. (I may not be phrasing that right)

[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]

I need all the values for item2 in a array for a bash script to be run on ubuntu 14.04.1.

I have found a bunch of ways to get the entire result into an array but not just the items I need

15

Using :

$ cat json
[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]

CODE:

arr=( $(jq -r '.[].item2' json) )
printf '%s\n' "${arr[@]}"

OUTPUT:

value2
value2_2
  • Is it possible to do this from a variable instead of a file? I try to avoid excess filesystem access if I don't need it. Once I pull this array I am done with the json output. – JpaytonWPD Jan 7 '15 at 0:10
  • 1
    Have you tried something ? – Gilles Quenot Jan 7 '15 at 0:13
  • 2
    jq . <<< "$json" it's shell (bash) related, non specific to jq – Gilles Quenot Jan 7 '15 at 0:23
  • 1
    Missing parentheses : arr=( $(...) ) – Gilles Quenot Jan 7 '15 at 0:35
  • 3
    Great jq command, but please don't parse command output into an array with arr=( $(...) ) (even though it happens to work with the sample input): it doesn't work as intended with embedded or leading/trailing whitespace and can result in accidental globbing. – mklement0 Jul 14 '16 at 5:21
3

The following is actually buggy:

# BAD: Output line of * is replaced with list of local files; can't deal with whitespace
arr=( $( curl -k "$url" | jq -r '.[].item2' ) )

Instead, use:

# GOOD (with bash 4.x+), but can't detect failure
readarray -t arr < <(curl -k "$url" | jq -r '.[].item2' )

...or, even better...

# GOOD (with bash 3.x+), *and* has nonzero status if curl or jq fails
IFS=$'\n' read -r -d '' -a arr \
  < <(set -o pipefail; curl --fail -k "$url" | jq -r '.[].item2' && printf '\0')
2

Thanks to sputnick I got to this:

arr=( $(curl -k https://localhost/api | jq -r '.[].item2') )

The JSON I have is the output from an API. All I needed to do wans remove the file argument and pipe | the output of curl to jq. Works great and saved some steps.

  • That code's actually a bit buggy. Look at what happens if you have a result element of * -- it'll get replaced with a list of files in your current directory. – Charles Duffy Oct 5 '16 at 2:55
  • Similarly, an item2 value with whitespace in it would become more than one array element. – Charles Duffy Oct 5 '16 at 3:02
0

as an easy alternative, look at jtc tool (at https://github.com/ldn-softdev/jtc), to achieve the same thing (as in jq's example):

bash $ arr=( $(jtc -w '<item2>l+0' file.json) )
bash $ printf '%s\n' "${arr[@]}"
"value2"
"value2_2"
bash $ 

explanation on -w option: angular brackets <...> specify search entire json, suffix l instructs to search labels rather than values, +0 instructs to find all occurrences (rather than just first one).

  • Same bug as all the arr=( $(jq ...) ) answers, insofar as the contents are being string-split and glob-expanded to populate the array -- meaning spaces (not just newlines) create new elements, and elements that look like a glob expression are replaced by files that expression matches. – Charles Duffy Feb 1 at 14:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.