J'ai un script Bash. Il obtient les données au format JSON. Je dois convertir le tableau JSON en un tableau Bash.
Exemple
{
"SALUTATION": "Hello world",
"SOMETHING": "bla bla bla Mr. Freeman"
}
Dans Bash, je veux obtenir une valeur comme celle-ci echo ${arr[SOMETHING]}
.
Si vous voulez une clé et une valeur, et basé sur Comment convertir un objet Json au format clé = valeur dans JQ , vous pouvez faire:
$ jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" file
SALUTATION=Hello world
SOMETHING=bla bla bla Mr. Freeman
De manière plus générale, vous pouvez stocker les valeurs dans un tableau myarray[key] = value
comme ceci, simplement en fournissant jq
à while
avec la syntaxe while ... do; ... done < <(command)
:
declare -A myarray
while IFS="=" read -r key value
do
myarray[$key]="$value"
done < <(jq -r "to_entries|map(\"\(.key)=\(.value)\")|.[]" file)
Et ensuite, vous pouvez parcourir les valeurs suivantes:
for key in "${!myarray[@]}"
do
echo "$key = ${myarray[$key]}"
done
Pour cette entrée donnée, il retourne:
SALUTATION = Hello world
SOMETHING = bla bla bla Mr. Freeman
Contexte: Cette réponse a été écrite pour répondre à un titre de question qui n'existe plus. .
La question du PO décrit en fait les objets, vs les tableaux.
Pour être sûr que nous aidons les autres personnes qui viennent en fait recherchons de l'aide avec les tableaux JSON, il vaut toutefois la peine de les couvrir explicitement.
Dans le cas où les chaînes ne peuvent pas contenir de nouvelles lignes (et lorsque bash 4.0 ou plus récent est utilisé), cela fonctionne:
str='["Hello world", "bla bla bla Mr. Freeman"]'
readarray -t array <<<"$(jq -r '.[]' <<<"$str")"
Pour prendre en charge les anciennes versions de bash et des chaînes avec des nouvelles lignes, nous obtenons un peu plus sophistiqué, en utilisant un flux délimité par NUL pour lire à partir de jq
:
str='["Hello world", "bla bla bla Mr. Freeman", "this is\ntwo lines"]'
array=( )
while IFS= read -r -d '' line; do
array+=( "$line" )
done < <(jq -j '.[] | (. + "\u0000")')
Bien que cette question reçoive une réponse, je n’ai pas été en mesure de satisfaire pleinement mes exigences de Par rapport à la réponse affichée. Voici un petit article qui aidera tous les nouveaux arrivants .
Une déclaration de tableau associatif de base
#!/bin/bash
declare -A associativeArray=([key1]=val1 [key2]=val2)
Vous pouvez également utiliser des guillemets ('
, "
) autour de declaration
, ses keys
et values
.
#!/bin/bash
declare -A 'associativeArray=([key1]=val1 [key2]=val2)'
Et vous pouvez délimiter chaque paire [key]=value
via espace ou nouvelle ligne.
#!/bin/bash
declare -A associativeArray([key1]=value1
['key2']=value2 [key3]='value3'
['key4']='value2' ["key5"]="value3"
["key6"]='value4'
['key7']="value5"
)
En fonction de la variation de votre devis, vous devrez peut-être échapper votre chaîne.
Utilisation de Indirection pour accéder à la fois à la clé et à la valeur dans un tableau associatif
function example {
local -A associativeArray=([key1]=val1 [key2]=val2)
# print associative array
local key value
for key in "${!associativeArray[@]}"; do
value="${associativeArray["$key"]}"
printf '%s = %s' "$key" "$value"
done
}
Exécuter la fonction exemple
$ example
key2 = val2
key1 = val1
Connaître les friandises susmentionnées vous permet de dériver les extraits suivants:
Les exemples suivants auront tous le résultat comme l'exemple ci-dessus
#!/usr/bin/env bash
function example {
local arrayAsString='associativeArray=([key1]=val1 [key2]=val2)'
local -A "$arrayAsString"
# print associative array
}
#!/usr/bin/env bash
function example {
# Given the following JSON
local json='{ "key1": "val1", "key2": "val2" }'
# filter using `map` && `reduce`
local filter='to_entries | map("[\(.key)]=\(.value)") |
reduce .[] as $item ("associativeArray=("; . + ($item|@sh) + " ") + ")"'
# Declare and assign separately to avoid masking return values.
local arrayAsString;
arrayAsString=$(cat "$json" | jq --raw-output "${filter}")
local -A "$arrayAsString"
# print associative array
}
#!/usr/bin/env bash
function example {
# /path/to/file.json contains the same json as the first two examples
local filter filename='/path/to/file.json'
# including bash variable name in reduction
filter='to_entries | map("[\(.key | @sh)]=\(.value | @sh) ")
| "associativeArray=(" + add + ")"'
# using --argfile && --null-input
local -A "$(jq --raw-output --null-input --argfile file "$filename" \
"\$filename | ${filter}")"
# or for a more traceable declaration (using shellcheck or other) this
# variation moves the variable name outside of the string
# map definition && reduce replacement
filter='[to_entries[]|"["+(.key|@sh)+"]="+(.value|@sh)]|"("+join(" ")+")"'
# input redirection && --join-output
local -A associativeArray=$(jq --join-output "${filter}" < "${filename}")
# print associative array
}
@ Ján Lalinský
Pour charger efficacement un objet JSON dans un tableau associatif bash (Sans utiliser de boucles dans bash), vous pouvez utiliser l'outil 'jq', comme suit.
# first, load the json text into a variable: json='{"SALUTATION": "Hello world", "SOMETHING": "bla bla bla Mr. Freeman"}' # then, prepare associative array, I use 'aa': unset aa declare -A aa # use jq to produce text defining name:value pairs in the bash format # using @sh to properly escape the values aacontent=$(jq -r '. | to_entries | .[] | "[\"" + .key + "\"]=" + (.value | @sh)' <<< "$json") # string containing whole definition of aa in bash aadef="aa=($aacontent)" # load the definition (because values may contain LF characters, aadef must be in double quotes) eval "$aadef" # now we can access the values like this: echo "${aa[SOMETHING]}"
Attention: ceci utilise eval, ce qui est dangereux si l'entrée json provient d'une source inconnue (peut contenir des commandes Shell malveillantes pouvant être exécutées par eval).
Cela pourrait être réduit à la suivante
function example {
local json='{ "key1": "val1", "key2": "val2" }'
local -A associativeArray=("$(jq -r '. | to_entries | .[] |
"[\"" + .key + "\"]=" + (.value | @sh)' <<< "$json")")
# print associative array
}
@fedorqui
Si vous voulez une clé et une valeur, et basé sur Comment puis-je convertir un objet Json au format clé = valeur dans JQ , vous pouvez faire:
$ jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" file SALUTATION=Hello world SOMETHING=bla bla bla Mr. Freeman
De manière plus générale, vous pouvez stocker les valeurs dans un tableau
myarray[key] = value
comme ceci, simplement en fournissantjq
à lawhile
avec la syntaxewhile ... do; ... done < <(command)
:declare -A myarray while IFS="=" read -r key value do myarray[$key]="$value" done < <(jq -r "to_entries|map(\"\(.key)=\(.value)\")|.[]" file)
Et ensuite, vous pouvez parcourir les valeurs suivantes:
for key in "${!myarray[@]}" do echo "$key = ${myarray[$key]}" done
Pour cette entrée donnée, il retourne:
SALUTATION = Hello world SOMETHING = bla bla bla Mr. Freeman
La principale différence entre cette solution et la mienne réside dans le tableau En bash ou en jq.
Chaque solution est valide et, selon votre cas d'utilisation, l'une peut être plus utile Que l'autre.
Voici comment cela peut être fait de manière récursive:
#!/bin/bash
SOURCE="$PWD"
SETTINGS_FILE="$SOURCE/settings.json"
SETTINGS_JSON=`cat "$SETTINGS_FILE"`
declare -A SETTINGS
function get_settings() {
local PARAMS="$#"
local JSON=`jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" <<< "$1"`
local KEYS=''
if [ $# -gt 1 ]; then
KEYS="$2"
fi
while read -r PAIR; do
local KEY=''
if [ -z "$PAIR" ]; then
break
fi
IFS== read PAIR_KEY PAIR_VALUE <<< "$PAIR"
if [ -z "$KEYS" ]; then
KEY="$PAIR_KEY"
else
KEY="$KEYS:$PAIR_KEY"
fi
if jq -e . >/dev/null 2>&1 <<< "$PAIR_VALUE"; then
get_settings "$PAIR_VALUE" "$KEY"
else
SETTINGS["$KEY"]="$PAIR_VALUE"
fi
done <<< "$JSON"
}
Pour l'appeler:
get_settings "$SETTINGS_JSON"
Le tableau sera accédé comme ceci:
${SETTINGS[grandparent:parent:child]}
Pour charger efficacement un objet JSON dans un tableau associatif bash (sans utiliser de boucles dans bash), vous pouvez utiliser l'outil 'jq', comme suit.
# first, load the json text into a variable:
json='{"SALUTATION": "Hello world", "SOMETHING": "bla bla bla Mr. Freeman"}'
# then, prepare associative array, I use 'aa':
unset aa
declare -A aa
# use jq to produce text defining name:value pairs in the bash format
# using @sh to properly escape the values
aacontent=$(jq -r '. | to_entries | .[] | "[\"" + .key + "\"]=" + (.value | @sh)' <<< "$json")
# string containing whole definition of aa in bash
aadef="aa=($aacontent)"
# load the definition (because values may contain LF characters, aadef must be in double quotes)
eval "$aadef"
# now we can access the values like this: echo "${aa[SOMETHING]}"
Attention: ceci utilise eval, ce qui est dangereux si l'entrée json provient d'une source inconnue (peut contenir des commandes Shell malveillantes pouvant être exécutées par eval).