将 bash 变量传递给 jq

Posted

技术标签:

【中文标题】将 bash 变量传递给 jq【英文标题】:Passing bash variable to jq 【发布时间】:2017-02-22 22:55:22 【问题描述】:

我编写了一个脚本来从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"

【问题讨论】:

一个相关问题: 过滤器的语法略有不同 jq -r --arg var "$var" '.[$var]' ***.com/questions/34745451/… 【参考方案1】:

考虑也将 shell 变量 (EMAILID) 作为 jq 变量传递(这里也是 EMAILID,为了便于说明):

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

后记

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

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

输出是一个 JSON 字符串:

"foo@bar.com"

【讨论】:

这是唯一 100% 安全的答案;它让jq 使用该值正确创建过滤器,而不是使用bash 创建jq 解释为过滤器的字符串。 (考虑如果EMAILID 的值包含) 会发生什么。) 感谢高峰。您提供的解决方案是我正在寻找的正确响应。是的,它有效。 我的用例,它有效! function n2 termux-contact-list |jq -r --arg v1 "$1" '.[] | select(.name==$v1)|.number' 来电:n2 Name1 fyi,jq 的 env 函数在 jq 1.4 和 1.5+ 之间更改,因此对 env.EMAILID 的引用(在此答案的示例中)在 jq 1.4 中不起作用,因此建议使用 --arg EMAILID "$EMAILID"如果您需要使用 jq 1.4 ,请构建。希望这可以帮助;只是花了我一天的时间来为自己解决这个问题;) 使用--arg 传递的参数将作为字符串传递。如果要传递不同 JSON 类型的数据,请使用 --argjson,它将字符串解析为 JSON,例如,--argjson myObj '"a": [1, 2]'【参考方案2】:

我通过转义内部双引号解决了这个问题

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

【讨论】:

我使用它是因为 --arg 不能很好地与-c【参考方案3】:

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

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

在 bash 中你可以这样做

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

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

【讨论】:

完美运行。对于寻求快速解决方案的人来说并不太复杂。【参考方案4】:

有点无关,但我还是把它放在这里, 对于其他实际目的,shell 变量可以用作 -

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

【讨论】:

【参考方案5】:

这是一个报价问题,你需要:

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

如果您使用 单引号 来分隔主字符串,则 shell 会按字面意思使用 $EMAILID

“双引号”每个包含空格/元字符和每个扩展的文字:"$var""$(command "$var")""$array[@]""a & b"。将'single quotes' 用于代码或文字$'s: 'Costs $5 US'ssh host 'echo "$HOSTNAME"'。见http://mywiki.wooledge.org/Quoteshttp://mywiki.wooledge.org/Argumentshttp://wiki.bash-hackers.org/syntax/words

【讨论】:

在我的情况下也是错误的,如果根本不使用引号也类似:termux-contact-list |jq -r '.[] | select(.name=='$1')|.number'。结果:jq Compile error 我不知道为什么这条评论被投票了这么多次;是的,双引号允许变量扩展,但jq 不喜欢单引号:jq: error: syntax error, unexpected INVALID_CHARACTER (Unix shell quoting issues?) 如果您的输入是常规 json,那么它的值将是双引号(不是单引号)。工作原理:对 jq 的整个 arg 使用双引号并转义(使用 `\`)内的任何双引号,如 @asid 回答。 它不起作用。 如果你用单引号分隔主字符串,shell 会按字面意思使用 $EMAILID。 假设你设置了 $EMAILID="myemail@hotmail.com",那么命令 cat file.json | jq -r ".resource[] | select(.username=='$EMAILID') | .id" 实际上会以 cat file.json | jq -r ".resource[] | select(.username==myemail@hotmail.com) | .id" 运行并导致jq 的编译错误。 这让我走上了解决问题的道路。我的最终工作字符串 UPLOADED_ARNS=$(aws devicefarm list-uploads --arn $PROJECT_ARN | \ jq ".uploads[] | arn: .arn, name: .name | select (.name | contains(\" $FILE_EXTENSION\"))" | \ jq --raw-output '.arn')【参考方案6】:

实现此目的的另一种方法是使用 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

【讨论】:

【参考方案7】:

jq现在有更好的方法来访问环境变量,可以使用env.EMAILID

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

【讨论】:

【参考方案8】:

我知道有点晚才回复,抱歉。但这对我有用。

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

在我的例子中,我需要使用双引号和引号来访问变量值。

干杯。

【讨论】:

【参考方案9】:

如果我们想将一些字符串附加到变量值并且我们使用转义的双引号,例如将.crt附加到变量CERT_TYPE;以下应该有效:

$ CERT_TYPE=client.reader
$ cat certs.json | jq -r ".\"$CERT_TYPE\".crt" #### This will *not* work #####
$ cat certs.json | jq -r ".\"$CERT_TYPE.crt\""

【讨论】:

【参考方案10】:

我也遇到了同样的 jq 变量替换问题。我发现--arg 是必须与方括号[] 一起使用的选项,否则它将不起作用。我在下面给你示例:

RUNNER_TOKEN=$(aws secretsmanager get-secret-value --secret-id $SECRET_ID | jq '.SecretString|fromjson' | jq --arg kt $SECRET_KEY -r '.[$kt]' | tr -d '"')

【讨论】:

以上是关于将 bash 变量传递给 jq的主要内容,如果未能解决你的问题,请参考以下文章

Bash:导出未将变量正确传递给父级

如何将 Bash 变量传递给 Python?

将bash变量传递给python命令[关闭]

通过回声管道将python变量(字符串)传递给bash命令[重复]

将变量传递给Linux bash命令参数

Makefile将变量传递给bash脚本