Chuyển biến bash cho jq select


112

Tôi đã viết một kịch bản để lấy giá trị nhất định từ đó file.json. Nó hoạt động nếu tôi cung cấp giá trị cho jq select, nhưng biến dường như không hoạt động (hoặc tôi không biết cách sử dụng nó).

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

Một vấn đề liên quan: chuyển biến bash sang bộ lọc jq có cú pháp hơi khác jq -r --arg var "$var" '.[$var]' stackoverflow.com/questions/34745451/…
Tốt nhất

Câu trả lời:


176

Cũng nên xem xét việc chuyển biến shell (EMAILID) dưới dạng biến jq (ở đây cũng là EMAILID, để minh họa):

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

Tái bút

Đối với bản ghi, một khả năng khác sẽ là sử dụng envhàm của jq để truy cập các biến môi trường. Ví dụ: hãy xem xét chuỗi lệnh bash này:

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

Đầu ra là một chuỗi JSON:

"foo@bar.com"

4
Đây là câu trả lời 100% an toàn duy nhất; nó cho phép jqtạo bộ lọc đúng cách bằng cách sử dụng giá trị, thay vì sử dụng bashđể tạo chuỗi jqthông dịch như một bộ lọc. (Hãy xem xét những gì sẽ xảy ra nếu giá trị của EMAILIDchứa ).)
chepner

3
Cảm ơn đỉnh cao. giải pháp được cung cấp của bạn là phản hồi thích hợp mà tôi đang tìm kiếm. Có nó hoạt động.
asidd

Trường hợp sử dụng của tôi, nó hoạt động! function n2 { termux-contact-list |jq -r --arg v1 "$1" '.[] | select(.name==$v1)|.number' }Gọi:n2 Name1
Timo

2
fyi, envhàm của jq được thay đổi giữa jq 1.4 và 1.5+, do đó, các tham chiếu đến env.EMAILID(trong ví dụ của câu trả lời này) không hoạt động trong jq 1.4, do đó, bạn nên sử dụng --arg EMAILID "$EMAILID"cấu trúc nếu bạn cần sử dụng jq 1.4. Hi vọng điêu nay co ich; chỉ đã cho tôi một ngày + con số này ra cho bản thân mình;)
m0j0hn

3
Các đối số được chuyển bằng cách sử dụng --argsẽ được chuyển dưới dạng chuỗi. Nếu bạn muốn chuyển dữ liệu của một loại JSON khác, hãy sử dụng --argjson, sẽ phân tích cú pháp chuỗi thành JSON, ví dụ:--argjson myObj '{"a": [1, 2]}'
BallpointBen

25

Tôi đã giải quyết vấn đề này bằng cách thoát khỏi dấu ngoặc kép bên trong

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

Tôi đang sử dụng cái này vì --arg không chơi đẹp với-c
Dimitris Moraitidis

9

Đó là một vấn đề báo giá, bạn cần:

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

Nếu bạn đặt các dấu ngoặc kép để phân tách chuỗi chính, shell sẽ theo $EMAILIDnghĩa đen.

"Double quote" mỗi đen có chứa dấu cách / metacharacters và mỗi mở rộng: "$var", "$(command "$var")", "${array[@]}", "a & b". Sử dụng 'single quotes'mã hoặc đen $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Xem
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words


Trong trường hợp của tôi lỗi là tốt, tương tự nếu không sử dụng dấu ngoặc kép ở tất cả: termux-contact-list |jq -r '.[] | select(.name=='$1')|.number'. Kết quả:jq Compile error
Timo

6
Tôi không chắc tại sao bình luận này đã được bình chọn nhiều lần như vậy; vâng, dấu ngoặc kép cho phép mở rộng biến, nhưng jqkhông giống như dấu nháy đơn:jq: error: syntax error, unexpected INVALID_CHARACTER (Unix shell quoting issues?)
jdelman

Nếu đầu vào của bạn là json thông thường, thì các giá trị của nó sẽ được trích dẫn gấp đôi (không phải đơn). Cách hoạt động: Sử dụng dấu ngoặc kép cho toàn bộ đối số của jq và thoát (với `\ ') bất kỳ dấu ngoặc kép nào bên trong, như @asid đã trả lời.
GuSuku

5

Đăng nó ở đây vì nó có thể giúp ích cho những người khác. Trong chuỗi, có thể cần phải chuyển các dấu ngoặc kép cho jq. Để làm như sau với jq:

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

trong bash bạn có thể làm

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

về cơ bản là thoát khỏi các dấu ngoặc kép và chuyển nó sang jq


Hoạt động hoàn hảo. Không quá phức tạp cho một người đang tìm kiếm một giải pháp nhanh chóng.
Mo-Gang

4

Một cách khác để thực hiện điều này là với cờ jq "--arg". Sử dụng ví dụ ban đầu:

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

Xem tại đây, đó là nơi tôi tìm thấy giải pháp này: https://github.com/stedolan/jq/issues/626


2

Tôi biết là một chút sau để trả lời, xin lỗi. Nhưng điều đó hiệu quả với tôi.

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

Và bây giờ tôi có thể tìm nạp và chuyển nội dung của biến vào 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')"

Trong trường hợp của tôi, tôi cần sử dụng dấu ngoặc kép và dấu ngoặc kép để truy cập giá trị biến.

Chúc mừng.


1

Jq bây giờ có cách tốt hơn để tích lũy các biến môi trường, bạn có thể sử dụng env.EMAILI:

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

0

Ít không liên quan nhưng tôi vẫn sẽ đặt nó ở đây, Đối với các mục đích thực tế khác, các biến shell có thể được sử dụng như:

value=10
jq  '."key" = "'"$value"'"' file.json
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.