Pasando la variable bash a jq select


112

He escrito un script para recuperar cierto valor file.json. Funciona si proporciono el valor a jq select, pero la variable no parece funcionar (o no sé cómo 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 relacionado: pasar la variable bash al filtro jq tiene una sintaxis ligeramente diferente jq -r --arg var "$var" '.[$var]' stackoverflow.com/questions/34745451/…
enharmonic

Respuestas:


176

Considere también pasar la variable de shell (EMAILID) como una variable jq (aquí también EMAILID, por el bien de la ilustración):

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

Posdata

Para el registro, otra posibilidad sería utilizar la envfunción de jq para acceder a las variables de entorno. Por ejemplo, considere esta secuencia de comandos de bash:

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

La salida es una cadena JSON:

"foo@bar.com"

4
Ésta es la única respuesta 100% segura; permite jqcrear correctamente el filtro usando el valor, en lugar de usarlo bashpara crear una cadena que se jqinterprete como un filtro. (Considere lo que sucede si el valor de EMAILIDcontiene a ).)
chepner

3
Gracias pico. su solución proporcionada es la respuesta adecuada que estaba buscando. Si, funciona.
asidd

Mi caso de uso, ¡funciona! function n2 { termux-contact-list |jq -r --arg v1 "$1" '.[] | select(.name==$v1)|.number' }Llamando:n2 Name1
Timo

2
Para su información, la envfunción de jq se cambia entre jq 1.4 y 1.5+, por lo que las referencias a env.EMAILID(en el ejemplo de esta respuesta) no funcionan en jq 1.4, por lo que se recomienda usar la --arg EMAILID "$EMAILID"construcción si necesita usar jq 1.4. Espero que esto ayude; me tomó un día + para resolver esto por mí mismo;)
m0j0hn

3
Los argumentos pasados ​​usando --argse pasarán como cadenas. Si desea pasar datos de un tipo JSON diferente, use --argjson, que analizará la cadena como JSON, por ejemplo,--argjson myObj '{"a": [1, 2]}'
BallpointBen

25

Resolví este problema escapando de las comillas dobles internas

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

Estoy usando esto porque --arg no juega bien con-c
Dimitris Moraitidis

9

Es un problema de cotización, necesita:

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

Si pone comillas simples para delimitar la cadena principal, el shell toma $EMAILIDliteralmente.

"Cita doble" cada literal que contiene espacios / metacaracteres y cada expansión: "$var", "$(command "$var")", "${array[@]}", "a & b". Utilizar 'single quotes'para el código o literal $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Ver
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words


En mi caso de error, así, similar, si no el uso de citas en absoluto: termux-contact-list |jq -r '.[] | select(.name=='$1')|.number'. Resultado:jq Compile error
Timo

6
No estoy seguro de por qué este comentario ha sido votado tantas veces; sí, las comillas dobles permiten la expansión de variables, pero jqno le gustan las comillas simples:jq: error: syntax error, unexpected INVALID_CHARACTER (Unix shell quoting issues?)
jdelman

Si su entrada es un json regular, entonces sus valores se cotizarían doble (no simple). Qué funciona: Usar comillas dobles para todo el argumento de jq y escapar (con `\`) cualquier comilla doble dentro, como @asid respondió.
GuSuku

6

Publicarlo aquí ya que podría ayudar a otros. En cadena, puede ser necesario pasar las comillas a jq. Para hacer lo siguiente con jq:

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

en bash podrías hacer

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

esencialmente escapando de las comillas y pasándolo a jq


Funciona perfectamente. No es demasiado complicado para alguien que busca una solución rápida.
Mo-Gang

4

Otra forma de lograr esto es con la bandera jq "--arg". Usando el ejemplo original:

#!/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"

Vea aquí, que es donde encontré esta solución: https://github.com/stedolan/jq/issues/626


2

Sé que es un poco más tarde para responder, lo siento. Pero eso funciona para mí.

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

Y ahora puedo buscar y pasar el contenido de la variable 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')"

En mi caso, necesitaba usar comillas dobles y comillas para acceder al valor de la variable.

Salud.


1

Jq ahora tiene una mejor manera de acceder a las variables de entorno, puede usar env.EMAILI:

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

0

Poco relacionado, pero lo pondré aquí, para otros propósitos prácticos, las variables de shell se pueden usar como:

value=10
jq  '."key" = "'"$value"'"' file.json
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.