J'ai des données JSON comme suit dans le fichier data.json
[
{"original_name":"pdf_convert","changed_name":"pdf_convert_1"},
{"original_name":"video_encode","changed_name":"video_encode_1"},
{"original_name":"video_transcode","changed_name":"video_transcode_1"}
]
Je veux parcourir le tableau et extraire la valeur de chaque élément d'une boucle. J'ai vu jq . J'ai du mal à l'utiliser pour répéter. Comment puis je faire ça?
Utilisez simplement un filtre qui retournerait chaque élément du tableau. Ensuite, parcourez les résultats, assurez-vous simplement d'utiliser l'option de sortie compacte (-c
) donc chaque résultat est placé sur une seule ligne et est traité comme un élément dans la boucle.
jq -c '.[]' input.json | while read i; do
# do stuff with $i
done
Essayez de le construire autour de cet exemple. (Source: site d'origine)
Exemple:
jq '[foreach .[] as $item ([[],[]]; if $item == null then [[],.[0]] else [(.[0] + [$item]),[]] end; if $item == null then .[1] else empty end)]'
Input [1,2,3,4,null,"a","b",null]
Output [[1,2,3,4],["a","b"]]
Une réponse antérieure dans ce fil a suggéré d'utiliser foreach
de jq, mais cela peut être beaucoup plus compliqué que nécessaire, surtout compte tenu de la tâche indiquée. Plus précisément, foreach
(et reduce
) sont destinés à certains cas où vous devez accumuler des résultats.
Dans de nombreux cas (y compris dans certains cas où une étape de réduction est éventuellement nécessaire), il est préférable d'utiliser .[]
Ou map(_)
. Ce dernier n'est qu'une autre façon d'écrire [. [] | _] donc si vous allez utiliser jq, il est vraiment utile de comprendre cela. [] crée simplement un stream de valeurs. Par exemple, [1,2,3] | .[]
Produit un flux des trois valeurs.
Pour prendre un exemple simple de réduction de carte, supposons que vous souhaitiez trouver la longueur maximale d'un tableau de chaînes. Une solution serait [ .[] | length] | max
.
jq
a une option de formatage Shell: @sh
.
Vous pouvez utiliser les éléments suivants pour formater vos données json en tant que paramètres Shell:
cat data.json | jq '. | map([.original_name, .changed_name])' | jq @sh
La sortie ressemblera à:
"'pdf_convert' 'pdf_convert_1'"
"'video_encode' 'video_encode_1'",
"'video_transcode' 'video_transcode_1'"
Pour traiter chaque ligne, nous devons faire deux ou trois choses:
Pour lire la ligne entière à chaque itération de la boucle for bash, définissez la variable IFS
, comme décrit dans cette réponse .
Pour supprimer les guillemets doubles, nous allons l'exécuter via l'interpréteur bash Shell en utilisant xargs
:
stripped=$(echo $original | xargs echo)
Dans l'ensemble, nous avons:
#!/bin/bash
function processRow() {
original_name=$1
changed_name=$2
# TODO
}
IFS=$'\n' # Each iteration of the for loop should read until we find an end-of-line
for row in $(cat data.json | jq '. | map([.original_name, .changed_name])' | jq @sh)
do
# Run the row through the Shell interpreter to remove enclosing double-quotes
stripped=$(echo $row | xargs echo)
# Call our function to process the row
# eval must be used to interpret the spaces in $stripped as separating arguments
eval processRow $stripped
done
unset IFS # Return IFS to its original value