
Tengo una salida JSON que contiene una lista de objetos almacenados en una variable. (Puede que no esté expresando eso bien)
[
{
"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 de item2 en una matriz para ejecutar un script bash en ubuntu 14.04.1.
He encontrado varias formas de obtener el resultado completo en una matriz, pero no solo los elementos que necesito.
Respuesta1
Usandojq:
readarray arr < <(jq '.[].item2' json)
printf '%s\n' "${arr[@]}"
Si necesita una forma más reforzada:
readarray -td '' arr
para entradas con nuevas líneas u otros caracteres especiales, evitando la división de palabras.
Producción:
value2
value2_2
Controlar:
Procesa la sustitución >(command ...)
o <(...)
se reemplaza por un nombre de archivo temporal. Escribir o leer ese archivo hace que los bytes se canalicen al comando interno. A menudo se utiliza en combinación con la redirección de archivos: cmd1 2> >(cmd2)
. Verhttp://mywiki.wooledge.org/ProcessSubstitution http://mywiki.wooledge.org/BashFAQ/024
Respuesta2
En realidad, lo siguiente tiene errores:
# BAD: Output line of * is replaced with list of local files; can't deal with whitespace
arr=( $( curl -k "$url" | jq -r '.[].item2' ) )
Si tiene bash 4.4 o posterior, hay disponible la mejor opción del mundo:
# BEST: Supports bash 4.4+, with failure detection and newlines in data
{ readarray -t -d '' arr && wait "$!"; } < <(
set -o pipefail
curl --fail -k "$url" | jq -j '.[].item2 | (., "\u0000")'
)
...mientras que con bash 4.0, puede ser conciso a costa de la detección de fallas y el soporte literal de nueva línea:
# OK (with bash 4.0), but can't detect failure and doesn't support values with newlines
readarray -t arr < <(curl -k "$url" | jq -r '.[].item2' )
...o compatibilidad con bash 3.x y detección de fallas, pero sin soporte de nueva línea:
# OK: Supports bash 3.x; no support for newlines in values, but can detect failures
IFS=$'\n' read -r -d '' -a arr < <(
set -o pipefail
curl --fail -k "$url" | jq -r '.[].item2' && printf '\0'
)
...o compatibilidad con bash 3.x y soporte de nueva línea, pero sin detección de fallas:
# OK: Supports bash 3.x and supports newlines in values; does not detect failures
arr=( )
while IFS= read -r -d '' item; do
arr+=( "$item" )
done < <(curl --fail -k "$url" | jq -j '.[] | (.item2, "\u0000")')
Respuesta3
Úselo jq
para producir una declaración de shell que evalúe:
eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"
Dado el documento JSON en su pregunta, la llamada jq
producirá la cadena
arr=( 'value2' 'value2_2' )
que luego es evaluado por su shell. La evaluación de esa cadena creará la matriz nombrada arr
con los dos elementos value2
y value2_2
:
$ eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"
$ printf '"%s"\n' "${arr[@]}"
"value2"
"value2_2"
El @sh
operador jq
se encarga de citar correctamente los datos del shell.
Alternativamente, saque la arr=( ... )
parte de la jq
expresión:
eval "arr=( $( jq -r '@sh "\([.[].item2])"' file.json ) )"
Ahora, jq
solo genera la lista de elementos citados, que luego se inserta arr=( ... )
y se evalúa.
Si necesita leer datos de un curl
comando, utilícelo curl ... | jq -r ...
en lugar de jq -r ... file.json
en los comandos anteriores.
Respuesta4
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.