Meneruskan variabel bash ke jq

113

Saya telah menulis skrip untuk mengambil nilai tertentu file.json. Ini berfungsi jika saya memberikan nilai ke jq select, tetapi variabel tampaknya tidak berfungsi (atau saya tidak tahu cara menggunakannya).

#!/bin/sh

#this works ***
projectID=$(cat file.json | jq -r '.resource[] | select(.username=="[email protected]") | .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"
asidd
sumber
Masalah terkait: meneruskan variabel bash ke filter jq memiliki sintaks yang sedikit berbeda jq -r --arg var "$var" '.[$var]' stackoverflow.com/questions/34745451/…
enharmonic

Jawaban:

177

Pertimbangkan juga untuk meneruskan variabel shell (EMAILID) sebagai variabel jq (di sini juga EMAILID, sebagai ilustrasi):

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

Nota bene

Sebagai catatan, kemungkinan lain adalah menggunakan envfungsi jq untuk mengakses variabel lingkungan. Misalnya, pertimbangkan urutan perintah bash ini:

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

Outputnya adalah string JSON:

"[email protected]"
puncak
sumber
4
Ini adalah satu-satunya jawaban yang 100% aman; ini memungkinkan jqmembuat filter dengan benar menggunakan nilai, daripada menggunakan bashuntuk membuat string yang jqditafsirkan sebagai filter. (Pertimbangkan apa yang terjadi jika nilai EMAILIDberisi a ).)
chepner
3
Terima kasih puncak. solusi yang Anda berikan adalah respons yang tepat yang saya cari. Ya, itu berhasil.
asidd
Kasus penggunaan saya, berhasil! function n2 { termux-contact-list |jq -r --arg v1 "$1" '.[] | select(.name==$v1)|.number' }Menelepon:n2 Name1
Timo
2
fyi, envfungsi jq diubah antara jq 1.4 dan 1.5+, jadi referensi ke env.EMAILID(dalam contoh jawaban ini) tidak berfungsi di jq 1.4, sehingga merekomendasikan penggunaan --arg EMAILID "$EMAILID"konstruksi jika Anda perlu menggunakan jq 1.4. Semoga ini membantu; hanya butuh satu hari + untuk memikirkannya sendiri;)
m0j0hn
3
Argumen yang diteruskan menggunakan --argakan diteruskan sebagai string. Jika Anda ingin meneruskan data dari jenis JSON yang berbeda, gunakan --argjson, yang akan mengurai string sebagai JSON, misalnya,--argjson myObj '{"a": [1, 2]}'
BallpointBen
25

Saya menyelesaikan masalah ini dengan keluar dari tanda kutip ganda batin

projectID=$(cat file.json | jq -r ".resource[] | select(.username==\"$EMAILID\") | .id")
asidd
sumber
Saya menggunakan ini karena --arg tidak cocok dengan-c
Dimitris Moraitidis
9

Ini masalah kutipan, Anda perlu:

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

Jika Anda meletakkan tanda kutip tunggal untuk membatasi string utama, shell akan memahami $EMAILIDsecara harfiah.

"Double quote" setiap literal yang berisi spasi / metakarakter dan setiap ekspansi: "$var", "$(command "$var")", "${array[@]}", "a & b". Gunakan 'single quotes'untuk kode atau literal $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Lihat
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words

Gilles Quenot
sumber
Dalam error kasus saya juga, sama jika tidak menggunakan kutipan sama sekali: termux-contact-list |jq -r '.[] | select(.name=='$1')|.number'. Hasil:jq Compile error
Timo
6
Saya tidak yakin mengapa komentar ini dipilih berkali-kali; ya, tanda kutip ganda memungkinkan untuk perluasan variabel, tetapi jqtidak menyukai tanda kutip tunggal:jq: error: syntax error, unexpected INVALID_CHARACTER (Unix shell quoting issues?)
jdelman
Jika masukan Anda adalah json biasa, maka nilainya akan menjadi ganda (bukan tunggal) dikutip. Apa yang berhasil: Menggunakan tanda kutip ganda untuk seluruh argumen jq dan meng-escape (dengan `\`) tanda kutip ganda di dalamnya, seperti @asid dijawab.
GuSuku
6

Posting di sini karena dapat membantu orang lain. Dalam string mungkin perlu untuk meneruskan tanda kutip ke jq. Untuk melakukan hal berikut dengan jq:

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

dalam pesta yang bisa Anda lakukan

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

pada dasarnya keluar dari tanda kutip dan meneruskannya ke jq

Zaid
sumber
Bekerja dengan sempurna. Tidak terlalu rumit untuk seseorang yang mencari solusi cepat.
Mo-Gang
4

Cara lain untuk melakukannya adalah dengan flag jq "--arg". Menggunakan contoh asli:

#!/bin/sh

#this works ***
projectID=$(cat file.json | jq -r '.resource[] | 
select(.username=="[email protected]") | .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"

Lihat di sini, di mana saya menemukan solusi ini: https://github.com/stedolan/jq/issues/626

Andrew Lockhart
sumber
2

Saya tahu agak terlambat untuk membalas, maaf. Tapi itu berhasil untuk saya.

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

Dan sekarang saya bisa mengambil dan meneruskan konten variabel ke 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')"

Dalam kasus saya, saya perlu menggunakan kutipan ganda dan kutipan untuk mengakses nilai variabel.

Bersulang.

Rodrigo Andrade
sumber
1

Jq sekarang memiliki cara yang lebih baik untuk mengakses variabel lingkungan, Anda dapat menggunakan env.EMAILI:

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

Sedikit tidak terkait tetapi saya akan tetap meletakkannya di sini, Untuk tujuan praktis lainnya variabel shell dapat digunakan sebagai -

value=10
jq  '."key" = "'"$value"'"' file.json
markroxor
sumber