Передача змінної bash до jq


112

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

#!/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 filter має дещо інший синтаксис jq -r --arg var "$var" '.[$var]' stackoverflow.com/questions/34745451/…
енхармонія

Відповіді:


176

Розглянемо також передачу змінної оболонки (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
Це єдина 100-безпечна відповідь; він дозволяє jqналежним чином створити фільтр за допомогою значення, а не використовувати bashдля створення рядка, що jqінтерпретує як фільтр. (Поміркуйте, що станеться, якщо значення EMAILIDмістить a ).)
чепнер

3
Дякуючий пік Ваше надане рішення - це відповідна відповідь, яку я шукав. Так, це працює.
відмовитись

Мій випадок використання, він працює! 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

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

25

Я вирішив це питання, уникаючи внутрішніх подвійних цитат

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

Я використовую це, тому що --арг не грає добре-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
Тимо

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")

в баші ви могли б зробити

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/isissue/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.