analizar un campo de una matriz JSON en una matriz bash

13

Tengo una salida JSON que contiene una lista de objetos almacenados en una variable. (Puede que no esté redactando ese derecho)

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

Necesito todos los valores para item2 en una matriz para que un script bash se ejecute en ubuntu 14.04.1.

He encontrado muchas formas de obtener el resultado completo en una matriz, pero no solo los elementos que necesito

JpaytonWPD
fuente

Respuestas:

17

Usando :

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

CÓDIGO:

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

SALIDA:

value2
value2_2
Gilles Quenot
fuente
¿Es posible hacer esto desde una variable en lugar de un archivo? Intento evitar el acceso excesivo al sistema de archivos si no lo necesito. Una vez que saco esta matriz, he terminado con la salida json.
JpaytonWPD
1
¿Has intentado algo?
Gilles Quenot
2
jq . <<< "$json"está relacionado con shell (bash), no específico dejq
Gilles Quenot
1
Paréntesis faltantes:arr=( $(...) )
Gilles Quenot
44
Gran jqcomando, pero no analice la salida del comando en una matriz con arr=( $(...) )(a pesar de que funciona con la entrada de muestra): no funciona según lo previsto con espacios en blanco incrustados o iniciales / finales y puede provocar un bloqueo accidental.
mklement0
5

Lo siguiente es realmente defectuoso:

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

En cambio, use:

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

...o mejor...

# 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')
Charles Duffy
fuente
2

Gracias a Sputnick llegué a esto:

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

El JSON que tengo es el resultado de una API. Todo lo que necesitaba hacer era eliminar el argumento del archivo y canalizar |la salida de curl a jq. Funciona muy bien y ahorró algunos pasos.

JpaytonWPD
fuente
Ese código es en realidad un poco defectuoso. Mira lo que sucede si tienes un elemento de resultado *: se reemplazará con una lista de archivos en tu directorio actual.
Charles Duffy el
1
Del mismo modo, un item2valor con espacios en blanco se convertiría en más de un elemento de matriz.
Charles Duffy,
0

Como alternativa fácil, mire la jtcherramienta (en https://github.com/ldn-softdev/jtc ), para lograr lo mismo (como en el ejemplo de jq):

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

explicación sobre la -wopción: los corchetes angulares <...>especifican la búsqueda completa de json, el sufijo lindica que busque etiquetas en lugar de valores, +0indica que encuentre todas las ocurrencias (en lugar de solo la primera).

Dmitry L.
fuente
El mismo error que todas las arr=( $(jq ...) )respuestas, en la medida en que el contenido se divide en cadenas y se expande globalmente para llenar la matriz, lo que significa que los espacios (no solo las nuevas líneas) crean nuevos elementos, y los elementos que parecen una expresión global se reemplazan por archivos que La expresión coincide.
Charles Duffy