Passando la variabile bash a jq


113

Ho scritto uno script da cui recuperare un determinato valore file.json. Funziona se fornisco il valore a jq select, ma la variabile non sembra funzionare (o non so come usarla).

#!/bin/sh

#this works ***
projectID=$(cat file.json | jq -r '.resource[] | select(.username=="myemail@hotmail.com") | .id')
echo "$projectID"

EMAILID=myemail@hotmail.com

#this does not work *** no value is printed
projectID=$(cat file.json | jq -r '.resource[] | select(.username=="$EMAILID") | .id')
echo "$projectID"

Un problema correlato: passa variabile bash per filtrare jq ha leggermente differente sintassi jq -r --arg var "$var" '.[$var]' stackoverflow.com/questions/34745451/...
enharmonic

Risposte:


177

Considera anche di passare la variabile di shell (EMAILID) come variabile jq (qui anche EMAILID, per motivi di illustrazione):

   projectID=$(cat file.json | 
     jq -r --arg EMAILID "$EMAILID" '
        .resource[]
        | select(.username==$EMAILID) 
        | .id')

Post scriptum

Per la cronaca, un'altra possibilità sarebbe quella di utilizzare la envfunzione di jq per accedere alle variabili d'ambiente. Ad esempio, considera questa sequenza di comandi bash:

EMAILID=foo@bar.com  # not exported
EMAILID="$EMAILID" jq -n 'env.EMAILID'

L'output è una stringa JSON:

"foo@bar.com"

4
Questa è l'unica risposta sicura al 100%; consente di jqcreare correttamente il filtro utilizzando il valore, anziché utilizzare bashper creare una stringa che jqinterpreta come un filtro. (Considera cosa succede se il valore di EMAILIDcontiene a ).)
chepner

3
Grazie picco. la tua soluzione fornita è la risposta corretta che stavo cercando. Sì funziona.
asidd

Il mio caso d'uso, funziona! function n2 { termux-contact-list |jq -r --arg v1 "$1" '.[] | select(.name==$v1)|.number' }Chiamata:n2 Name1
Timo

2
fyi, la envfunzione di jq è cambiata tra jq 1.4 e 1.5+, quindi i riferimenti a env.EMAILID(nell'esempio di questa risposta) non funzionano in jq 1.4, quindi si consiglia di utilizzare il --arg EMAILID "$EMAILID"costrutto se è necessario utilizzare jq 1.4. Spero che questo ti aiuti; mi ci è voluto un giorno + per capirlo da solo;)
m0j0hn

3
Gli argomenti passati utilizzando --argverranno passati come stringhe. Se desideri passare dati di un tipo JSON diverso, utilizza --argjson, che analizzerà la stringa come JSON, ad esempio--argjson myObj '{"a": [1, 2]}'
BallpointBen

25

Ho risolto questo problema evitando le virgolette doppie interne

projectID=$(cat file.json | jq -r ".resource[] | select(.username==\"$EMAILID\") | .id")

Lo sto usando perché --arg non gioca bene con-c
Dimitris Moraitidis il

9

È un problema di preventivo, hai bisogno di:

projectID=$(
  cat file.json | jq -r ".resource[] | select(.username=='$EMAILID') | .id"
)

Se inserisci virgolette singole per delimitare la stringa principale, la shell prende $EMAILIDletteralmente.

"Double citazione" ogni letterale che contiene spazi / metacaratteri e ogni espansione: "$var", "$(command "$var")", "${array[@]}", "a & b". Utilizzare 'single quotes'il codice o letterale $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Vedi
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words


Nel mio caso l'errore così, simile se non si utilizza le virgolette a tutti: termux-contact-list |jq -r '.[] | select(.name=='$1')|.number'. Risultato:jq Compile error
Timo

6
Non sono sicuro del motivo per cui questo commento sia stato votato così tante volte; sì, le virgolette doppie consentono l'espansione delle variabili, ma jqnon gradiscono le virgolette singole:jq: error: syntax error, unexpected INVALID_CHARACTER (Unix shell quoting issues?)
jdelman

Se il tuo input è un json regolare, i suoi valori sarebbero doppi (non singoli) tra virgolette. Cosa funziona: usare le virgolette doppie per l'intero argomento di jq e fare l'escape (con "\") di eventuali virgolette doppie all'interno, come @asid ha risposto.
GuSuku

6

Pubblicarlo qui perché potrebbe aiutare gli altri. In stringa potrebbe essere necessario passare le virgolette a jq. Per fare quanto segue con jq:

.items[] | select(.name=="string")

in bash potresti fare

EMAILID=$1
projectID=$(cat file.json | jq -r '.resource[] | select(.username=='\"$EMAILID\"') | .id')

essenzialmente sfuggendo alle virgolette e passandole a jq


Funziona perfettamente. Non troppo complicato per chi cerca una soluzione rapida.
Mo-Gang

4

Un altro modo per ottenere ciò è con il flag jq "--arg". Utilizzando l'esempio originale:

#!/bin/sh

#this works ***
projectID=$(cat file.json | jq -r '.resource[] | 
select(.username=="myemail@hotmail.com") | .id')
echo "$projectID"

EMAILID=myemail@hotmail.com

# Use --arg to pass the variable to jq. This should work:
projectID=$(cat file.json | jq --arg EMAILID $EMAILID -r '.resource[] 
| select(.username=="$EMAILID") | .id')
echo "$projectID"

Vedi qui, che è dove ho trovato questa soluzione: https://github.com/stedolan/jq/issues/626


2

So che è un po 'più tardi per rispondere, scusa. Ma per me funziona.

export K8S_public_load_balancer_url="$(kubectl get services -n ${TENANT}-production -o wide | grep "ingress-nginx-internal$" | awk '{print $4}')"

E ora sono in grado di recuperare e passare il contenuto della variabile a jq

export TF_VAR_public_load_balancer_url="$(aws elbv2 describe-load-balancers --region eu-west-1 | jq -r '.LoadBalancers[] | select (.DNSName == "'$K8S_public_load_balancer_url'") | .LoadBalancerArn')"

Nel mio caso avevo bisogno di utilizzare virgolette doppie e virgolette per accedere al valore della variabile.

Saluti.


1

Jq ora ha un modo migliore per accedere alle variabili d'ambiente, puoi usare env.EMAILI:

projectID=$(cat file.json | jq -r ".resource[] | select(.username==env.EMAILID) | .id")

0

Poco non correlato ma lo metterò ancora qui, per altri scopi pratici le variabili di shell possono essere utilizzate come -

value=10
jq  '."key" = "'"$value"'"' file.json
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.