Передача переменной bash в jq


114

Я написал сценарий для извлечения определенного значения file.json. Это сработает select, если я предоставлю значение jq , но переменная не работает (или я не знаю, как ее использовать).

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

Связанная проблема: передача переменной bash в фильтр jq имеет немного другой синтаксис jq -r --arg var "$var" '.[$var]' stackoverflow.com/questions/34745451/…
enharmonic

Ответы:


182

Также рассмотрите возможность передачи переменной оболочки (EMAILID) в качестве переменной jq (здесь также EMAILID для иллюстрации):

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

Постскриптум

Для записи, другой возможностью было бы использовать envфункцию jq для доступа к переменным среды. Например, рассмотрим эту последовательность команд bash:

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

Результатом является строка JSON:

"foo@bar.com"

4
Это единственный стопроцентно надежный ответ; он позволяет jqправильно создать фильтр, используя значение, а не использовать его bashдля создания строки, jqинтерпретируемой как фильтр. (Подумайте, что произойдет, если значение EMAILIDсодержит a ).)
chepner

3
Пик спасибо. предоставленное вами решение - это правильный ответ, который я искал. Да, это работает.
asidd

Мой вариант использования, это работает! function n2 { termux-contact-list |jq -r --arg v1 "$1" '.[] | select(.name==$v1)|.number' }Звонок:n2 Name1
Тимо

2
fyi, envфункция jq изменяется между jq 1.4 и 1.5+, поэтому ссылки на env.EMAILID(в этом примере ответа) не работают в jq 1.4, поэтому рекомендуется использовать --arg EMAILID "$EMAILID"конструкцию, если вам нужно использовать jq 1.4. Надеюсь это поможет; просто мне понадобился день +, чтобы разобраться в этом для себя;)
m0j0hn 04

3
Аргументы, переданные с использованием, --argбудут переданы в виде строк. Если вы хотите передать данные другого типа JSON, используйте --argjson, который будет анализировать строку как JSON, например,--argjson myObj '{"a": [1, 2]}'
BallpointBen

26

Я решил эту проблему, избежав внутренних двойных кавычек

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

Я использую это, потому что --arg плохо сочетается с-c
Димитрис Мораитидис

9

Это вопрос цитаты, вам нужно:

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

Если вы поместите одиночные кавычки, чтобы ограничить основную строку, оболочка принимает $EMAILIDбуквально.

«Двойная кавычка» каждый литерал , который содержит пробелы / метасимволы и каждое расширение: "$var", "$(command "$var")", "${array[@]}", "a & b". Используйте 'single quotes'для кода или буквального $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. См.
Http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words.


В моем случае ошибки , а также, похоже , если не использовать кавычки вообще: termux-contact-list |jq -r '.[] | select(.name=='$1')|.number'. Результат:jq Compile error
Timo

6
Я не уверен, почему за этот комментарий голосовали так много раз; да, двойные кавычки допускают расширение переменных, но jqне любят одинарные кавычки:jq: error: syntax error, unexpected INVALID_CHARACTER (Unix shell quoting issues?)
jdelman

Если ваш ввод - обычный json, то его значения будут заключены в двойные (а не одинарные) кавычки. Что работает: использование двойных кавычек для всего аргумента jq и экранирование (с помощью `\`) любых двойных кавычек внутри, например, @asid.
GuSuku

6

Разместите это здесь, так как это может помочь другим. В строке может потребоваться передать кавычки в jq. Чтобы сделать с jq следующее:

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

в bash вы могли бы сделать

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

по существу избегая кавычек и передавая их в jq


Прекрасно работает. Не слишком сложно для тех, кто ищет быстрое решение.
Mo-Gang

4

Другой способ сделать это - использовать флаг jq "--arg". Используя исходный пример:

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

См. Здесь, где я нашел это решение: https://github.com/stedolan/jq/issues/626


2

Я знаю, что чуть позже отвечу, извините. Но у меня это работает.

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

И теперь я могу получить и передать содержимое переменной 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')"

В моем случае мне нужно было использовать двойные кавычки и кавычки для доступа к значению переменной.

Ура.


1

У Jq теперь есть лучший способ доступа к переменным среды, вы можете использовать env.EMAILI:

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

0

Немного не связано, но я все равно помещу его здесь.Для других практических целей переменные оболочки могут использоваться как -

value=10
jq  '."key" = "'"$value"'"' file.json
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.