2017-10-09 3 views
0

Je souhaite détecter une erreur en fonction d'un champ JSON de message d'erreur vide ou non vide. J'utilise jq pour trancher le membre, mais j'ai alors beaucoup de mal à l'évaluer dans mon bash "si".bash JSON avec jq - comment vérifier la présence de membres JSON vides?

Je dispose d'un fichier JSON référencé par ma variable d'entrée de $ qui ne possède un membre errMsg, mais comme une chaîne vide (notez que mon invite CLI est ~ $):

~$ echo $(jq "." $input) 
{ "projectCode": "145", "fullCode": "1", "errMsg": "" } 

récupérer le champ errMsg dans ce cas donne correctement une chaîne vide:

~$ err=$(jq ".errMsg" $input) 
~$ echo $err 
"" 

problème: tester cette variable semble impossible:

~$ if [ $err = "" ]; then echo EMPTY; else echo CONTENT; fi 
CONTENT 

J'ai excité le VIDE comme $ err a juste montré "". Vérification inverse:

~$ if [ $err != "" ]; then echo EMPTY; else echo CONTENT; fi 
EMPTY 

donc $ err est apparemment pas "", même si l'écho des rendements err de $ ""? Comment cela peut-il être? Quelle caractéristique de bash suis-je manquant ici?

Quoi qu'il en soit, laisse essayer avec un JSON non vide (après avoir modifié le contenu d'entrée de $):

~$ echo $(jq "." $input) 
{ "projectCode": "145", "fullCode": "1", "errMsg": "not empty" } 
~$ echo $err 
"not empty" 

~$ if [ $err != "" ]; then echo EMPTY; else echo CONTENT; fi 
bash: syntax error near unexpected token `then' 

correct, puis masquer comme ceci:

~$ if [ "$err" != "" ]; then echo EMPTY; else echo CONTENT; fi 
bash: syntax error near unexpected token `then' 

Je suppose qu'il trouve un deuxième jeton après "pas" et ne l'aime pas. Après beaucoup de recherches je trouver cette solution vraiment illisible qui semble fonctionner:

~$ val=$(sed "s/^\(\"\)\(.*\)\1\$/\2/g" <<<"$err" | sed -e 's/\s.*$//') 
~$ if [ "$val" = "" ]; then echo "NO ERROR"; else echo "ERROR"; fi 
NO ERROR 

cela fonctionne aussi pour les membres de errmsg non vides. S'il vous plaît, il doit y avoir une solution simple et élégante à cela.

+0

'[$ err =" "]' n'est pas sûr code bash; rien à voir avec 'jq'. Si 'err' est vide, alors il exécute' [= ""] ', ce qui n'est pas une syntaxe valide. Vous avez besoin de '[" $ err "=" "]'. –

+0

Comme pour '' 'if [" $ err "! =" "]; alors écho VIDE; else echo CONTENU; fi''' - vraiment, vraiment * n'est pas * une erreur de syntaxe (bien que le '! =' signifie qu'il y a une erreur de logique). Voyez-le fonctionner correctement sur https://ideone.com/CblHNK –

+0

... si vous pouviez fournir un [mcve] sous forme de code, d'autres personnes pourraient copier-coller pour reproduire ce bug particulier (idéalement, un reproducteur testé pour travailler sur ideone ou un autre bac à sable tiers impartial), je serais très intéressé de le voir. –

Répondre

1

Passons en revue cela par le haut afin que vous compreniez ce qui se passe.

~$ err=$(jq ".errMsg" $input) 
~$ echo $err 
"" 

Cette sortie indique que err contient "" (il peut aussi avoir des espaces avant et après la ""). Ce n'est pas la même chose qu'une chaîne vide. Il s'agit littéralement de deux guillemets.

~$ if [ $err = "" ]; then echo EMPTY; else echo CONTENT; fi 
CONTENT 

J'excpected le VIDES comme $ err juste montré "".

Comme mentionné précédemment, $err n'est pas vide, il contient deux guillemets. En revanche, dans l'instruction Bash [ ... = "" ], le "" signifie réellement une valeur vide.

La déclaration Bash [ $err = "" ] est problématique, car elle se traduira par une erreur de syntaxe si la valeur de $err est vide, ou si elle contient des espaces blancs (en supposant que vous n'avez pas personnalisé IFS).

La bonne façon d'écrire cette déclaration à joindre $err guillemets doubles:

if [ "$err" = "" ]; then echo EMPTY; else echo CONTENT; fi 

va de même pour la variable $input dans votre première commande, il doit être écrit comme:

err=$(jq ".errMsg" "$input") 

Si vous voulez rechercher la valeur .errMsg vide dans l'objet, vous avez au moins deux options. Option 1: vérifier que la valeur est "".

if [ "$err" = '""' ]; then echo EMPTY; else echo CONTENT; fi 

Option 2: faire jq sortie en mode brut, il ne comprend pas les guillemets doubles enserrant autour des valeurs de chaîne.

err=$(jq -r ".errMsg" "$input") 
if [ "$err" = "" ]; then echo EMPTY; else echo CONTENT; fi 

Je recommande cette dernière option, de sorte que la valeur de err sera la valeur réelle. Les doubles guillemets qui entourent semblent juste le bruit pour votre but.

+0

merci, que jq -r est juste ce qu'il fallait. Court, concis, fonctionne. Plus besoin de sed. – onouv

+0

@onouv si cela répond à votre question, alors peut-être vous pouvez le marquer comme accepté. – janos

1

Vous pouvez lire votre structure entière dans un tableau associatif bash natif comme suit:

declare -A data=() 
while IFS=$'\t' read -r key value; do 
    data[$key]=$value 
done < <(jq -r 'to_entries[] | [.key, .value] | @tsv' "$input") 

À partir de là, vous avez plusieurs options: Vous pouvez vérifier les éléments individuellement ...

[[ ${data[errMsg]} ]] || echo "ERROR: errMsg is not set!" 

. ..ou vous pouvez boucler sur l'ensemble d'entre eux:

for key in "${!data[@]}"; do 
    [[ ${data[$key]} ]] || echo "ERROR: ${key} is not set!" 
done