bash: Itération sur les membres d'un tableau JSON sélectionné par index
Je suis en utilisant jq
pour analyser un fichier JSON, l'extraction de chaque tableau JSON dans une série dans une coquille de tableau.
Mon code actuel se présente comme suit:
for ((i = 0; i < ${#nvars[@]}; i++)); do
v1=($(cat $INPUT | jq '."config"[i]."var1"[]'))
echo $v1
done
message d'erreur:
error: i is not defined
J'ai aussi remplacé
v1=($(cat $INPUT | jq '."config"[i]."var1"[]'))
avec
v1=($(cat $INPUT | jq '."config"[$i]."var1"[]'))
ne fonctionne toujours pas. Une idée? Toute aide est appréciée!
Edit: Exemple De Données D'Entrée
{
"config-vars":[
{
"var1":["v1","v2"],
"var2":""
},
{
"var1":["v3",""],
"var2":"v4"
}
]
}
- Il y a quelques très détaillée des réponses ici. Ma solution préférée, bien que sa pertinence repose sur le contrôle des flux de votre script:
each_obj() { local cmd="$1" json_arr="$2" len i; len=$(jq 'length' <(echo "$json_arr")); for (( i=0; i<len; i+=1 )); do $cmd "$(jq ".[$i]" <(echo "$json_arr"))"; done; }
- Je suggère d'inverser un peu:
json_arr="$1"; shift
, et puis vous pouvez utiliser"$@"
pour exécuter une commande composée de tous les autres arguments sans risquer les enjeux de la mywiki.wooledge.org/BashFAQ/050 grâce à l'utilisation de$cmd
.
Vous devez vous connecter pour publier un commentaire.
Il y a un peu juste de la place pour de l'amélioration. Nous allons commencer ici:
...tout d'abord, vous n'avez pas besoin d'utiliser
cat
; il ralentit les performances de votre, parce que c'forcesjq
à lire à partir d'un tuyau plutôt que de partir de votre fichier d'entrée directement. Juste en cours d'exécutionjq <"$INPUT"
serait plus robuste (ou, mieux,<"$input"
, d'éviter d'utiliser des majuscules des noms, qui sont réservées par la convention pour la coquille objets internes et les variables d'environnement).Deuxièmement, vous avez besoin de citer toutes les extensions de variable, y compris l'expansion de l'entrée nom du fichier -- sinon, vous aurez des bugs à chaque fois que votre nom de fichier contient des espaces.
Troisième,
array=( $(stuff) )
divise la sortie destuff
sur tous les caractères de l'IFS, et étend les résultats de fractionnement dans une série de glob expressions (donc si la sortie contient*.txt
, et vous êtes en cours d'exécution de ce script dans un répertoire qui contient des fichiers de texte, vous les noms de ces fichiers dans votre matrice de résultats). Le fractionnement sur les retours à la ligne seulement signifie que vous pourriez analyser correctement multi-parole des chaînes, et la désactivation de glob expansion est nécessaire avant que vous pouvez utiliser cette technique de manière fiable en présence de glob caractères. Une façon de le faire est de fixerIFS=$'\n'
et exécuterset -h
avant d'exécuter cette commande; une autre est de rediriger la sortie de votre commande dans unwhile read
boucle (voir ci-dessous).Quatrième, remplacement de chaîne de caractères dans le code est une mauvaise pratique dans n'importe quelle langue; ainsi se trouve (locaux équivalents) Bobby Tables, permettant à quelqu'un qui est censé être en mesure de changer uniquement les données transmises dans le processus afin de fournir un contenu qui est traité dans le code de l'exécutable (quoique, dans ce cas, comme un
jq
script, ce qui est moins dangereux que l'exécution de code arbitraire dans une plus complète de la langue; encore, cela peut permettre de données supplémentaires pour être ajouté à la sortie).Ensuite, une fois que vous obtenez
jq
à émettre de la nouvelle ligne séparée du contenu, vous n'avez pas besoin de le lire dans un tableau: Vous pouvez parcourir le contenu comme il l'écrit à partir dejq
et de lire dans votre coquille, l'empêchant ainsi de la coque du besoin d'allouer de la mémoire à tampon, contenu:Enfin-disons que vous ne voulez travailler avec un tableau. Il y a deux façons de le faire que d'éviter des écueils. Est de mettre en
IFS
explicitement et désactiver glob expansion avant la mission:L'autre est à attribuer à votre tableau avec une boucle:
...ou, comme suggéré par @JohnKugelman, à utiliser
read -a
de lire l'ensemble du tableau en une seule opération:nvars=($(jq --arg i "$i" '."config-vars"[$i]."var1"[]' "$INPUT"))
mais l'obtention d'erreur:jq: error: Cannot index array with string
. Suis-je en train de faire quelque chose de mal? Merci!i
vous êtes de passage?-r
(--raw-output
) est une bonne idée, sinon, jq de sortie contient des caractères comme des citations que le shell ne pas analyser correctement au cours de mot de fractionnement, mais au contraire les traiter comme des données littérales.read -a
?IFS=$'\n' read -r -d '' -a result
de travail sur le dessus de ma tête, mais permettez-moi de réellement tester...jq
suppose que toutes les entrées via--arg
est une chaîne de caractères; que, en effet, de poser un problème pour essayer de les utiliser--arg
ici. Je suis à la recherche à la disponibilité des solutions de contournement.$i | tonumber
à l'intérieur de l'jq requête convertir la valeur d'un entier.jq -r --arg i 1 '.["config-vars"][$i | tonumber].var1[]' <test.json
travaille avec les données que vous avez fournies dans votre question.tonumber
fonctionne! Merci de sauver ma journée!read -a
forme dans les réponses (l'un dans les commentaires était très bien); excuses si vous essayez de l'utiliser, maintenant corrigé.Variables ne sont pas interpolées à l'intérieur des guillemets simples. L'utilisation des guillemets au lieu de cela, et de supprimer les guillemets.
Ou utiliser le
--arg
option et ensuite vous pouvez coller avec des guillemets simples.Vous pouvez également fixer l'inutile l'utilisation du chat:
Voir aussi @CharlesDuffy de réponse pour une grande explication détaillée des raisons affectation de tableau comme cela est dangereux.
.[\"config-vars\"][$i]
.jq
peut être dit d'être plus utile, il a un mode où la sortie est de retour à la ligne délimitée par des, permettant aux plus robuste de l'opération de fractionnement sur toute IFS caractère.--arg
; je viens de commenter, et vu qu'il était dans.jq
émet*
, il va être remplacé par une liste de noms de fichiers dans le répertoire local dans le tableau résultant.Si vous avez déjà stocké le résultat de certains JSON dans une variable appelée $MA_VAR:
Il m'a fallu beaucoup trop de temps à le comprendre. Tous les exemples que j'ai vus étaient compliquées, et j'ai dû pièce de cet ensemble.
jq
est capable d'extraire la structure en une seule fois, de sorte que la totalité de la boucle est superflu. Si l'entrée JSON contient plus d'enregistrements que vous avez des valeurs dansnvars
, utilisez l'index pour les hacher.