You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Bash变量传入jq过滤器并将完整命令存入变量?

问题描述

我有一个示例JSON文件/tmp/test.json,内容如下:

{
    "foo" : "val1",
    "bar" : "val2"
}

将键名存入变量后,执行以下命令能正常输出对应值:

key=foo
cat /tmp/test.json | jq --arg k $key '.[$k]'
# 输出:"val1"

但尝试将完整命令存入变量CMD后执行eval "$CMD"时出现错误:

CMD=`echo cat /tmp/test.json | jq --arg k $key '.[$k]'`
eval "$CMD"
# 错误输出:jq: parse error: Invalid numeric literal at line 1, column 4

请问该如何正确转义特殊字符,让命令存入变量后能正常执行?


解决方法

方法1:双引号包裹并转义特殊字符

直接用双引号定义变量,转义内部的$避免shell提前解析,同时保留jq所需的单引号:

key=foo
CMD="cat /tmp/test.json | jq --arg k $key '\.[\$k]'"
# 查看命令内容
echo "$CMD"
# 执行命令
eval "$CMD"

这里的\$k会在eval执行时被解析为$k,正确传递给jq作为参数。

方法2:Here-doc赋值(免复杂转义)

用here-doc可以原样写入命令,避免手动转义:

key=foo
# 单引号包裹EOF,内部变量不会提前解析
read -r -d '' CMD <<'EOF'
cat /tmp/test.json | jq --arg k "$key" '.[$k]'
EOF
# 查看命令
echo "$CMD"
# 执行命令
eval "$CMD"

如果需要提前替换$key的值,去掉EOF的单引号即可(写成<<EOF)。

方法3:数组存储命令(推荐)

在bash中用数组存储命令是更安全的方式,能避免eval带来的潜在风险:

key=foo
# 存储完整命令(包含管道)
CMD=(cat /tmp/test.json '|' jq --arg k "$key" '.[$k]')
# 执行命令
eval "${CMD[*]}"

# 更稳妥的拆分方式(避免eval处理管道)
JQ_CMD=(jq --arg k "$key" '.[$k]')
cat /tmp/test.json | "${JQ_CMD[@]}"

数组能自动处理参数中的特殊字符,无需手动转义。


错误原因分析

你最初的命令出错有两个核心原因:

  1. 反引号执行时,管道会被提前解析,echo cat /tmp/test.json的输出被当作jq的输入,而非把整个cat ... | jq ...作为命令字符串存入变量;
  2. 单引号在反引号环境中被shell解析,导致jq接收到的参数被提前替换(比如.[$k]变成.[foo]),破坏了jq的语法结构。

内容的提问来源于stack exchange,提问作者hydradon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 18:52:42