将bash变量传递给jq select


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滤波器有稍微不同的语法jq -r --arg var "$var" '.[$var]' stackoverflow.com/questions/34745451/...
等音

Answers:


176

还考虑将shell变量(EMAILID)作为jq变量(为便于说明,此处也称为EMAILID)传递:

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

后记

作为记录,另一种可能性是使用jq env函数访问环境变量。例如,考虑以下bash命令序列:

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

输出是一个JSON字符串:

"foo@bar.com"

4
这是唯一100%安全的答案;它允许jq使用值正确创建过滤器,而不是bash用于创建jq解释为过滤器的字符串。(请考虑如果的值EMAILID包含)。会发生什么。)
chepner

3
感谢高峰。您提供的解决方案是我一直在寻找的正确答案。是的,它有效。
2013年

我的用例,可以用!function n2 { termux-contact-list |jq -r --arg v1 "$1" '.[] | select(.name==$v1)|.number' }致电:n2 Name1
Timo

2
fyi,jq的env功能在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")

我之所以使用它,是因为--arg与-c
Dimitris Moraitidis在

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的整个arg使用双引号,并转义(带有\)(例如,@ asid已回答)。
GuSuku

6

将其发布在这里可能会帮助其他人。在字符串中,可能有必要将引号传递给jq。使用jq执行以下操作:

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

你可以做

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

本质上是将引号转义并将其传递给jq


完美运作。对于寻求快速解决方案的人来说并不太复杂。
莫刚

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

jQuery现在拥有访问环境变量的更好方法,您可以使用env.EMAILI:

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

0

无关紧要,但我仍将其放在此处,出于其他实际目的,shell变量可用作-

value=10
jq  '."key" = "'"$value"'"' file.json
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.