jq和bash:使用--arg的对象构造不起作用

时间:2017-07-24 20:26:19

标签: bash jq

给出以下输入:

J='{"a":1,"b":10,"c":100}  
{"a":2,"b":20,"c":200}  
{"a":3,"b":30,"c":300}'  

命令

SELECT='a,b'; echo $J | jq -c -s --arg P1 $SELECT '.[]|{a,b}'  

生成

{"a":1,"b":10}  
{"a":2,"b":20}  
{"a":3,"b":30}  

但是此命令会产生意外结果:

SELECT='a,b'; echo $J | jq -c -s --arg P1 $SELECT '.[]|{$P1}'  
{"P1":"a,b"}
{"P1":"a,b"}
{"P1":"a,b"}

如何让jq直接处理arg字符串?

使用tostring会出错

SELECT='a,b'; echo $J | jq -c -s --arg P1 $SELECT '.[]|{$P1|tostring}'  
jq: error: syntax error, unexpected '|', expecting '}' (Unix shell quoting
issues?) at <top-level>, line 1:  
.[]|{$SELECT|tostring}           
jq: 1 compile error  

SELECT需要是一个变量,而不是在脚本中硬编码。

2 个答案:

答案 0 :(得分:2)

如果您真的希望将数据解析为语法...

这不是--arg的合适用例。相反,替换为代码:

select='a,b'; jq -c -s '.[]|{'"$select"'}' <<<"$j"

请注意,这具有代码注入的所有常见警告:如果输入不受控制,则输出(或脚本的其他行为,特别是jq将来获得更强大的I / O功能时)应该同样可以考虑。

如果要将文字字符串拆分为键列表...

在这里,我们采用您的select_stra,b形式),并生成地图:{'a': 'a', 'b': 'b'};然后,我们可以将每个数据项分成条目,只选择地图中的项目,然后输出。

jq --arg select_str "$select" '
($select_str
 | split(",")
 | reduce .[] as $item ({}; .[$item]=$item)) as $select_map
 | with_entries(select($select_map[.key]))' <<<"$j"

答案 1 :(得分:2)

  

SELECT需要是一个变量,而不是在脚本中硬编码。

假设您希望避免“代码注入”的风险,并且您希望shell变量SELECT是一个简单的字符串,例如“a,b”,那么请考虑您尝试的这种无减少解决方案:

J='{"a":1,"b":10,"c":100}'
SELECT='a,b'
echo "$J" |
  jq -c --arg P1 "$SELECT" '
    . as $in | $P1 | split(",") | map( {(.): $in[.]} ) | add'

输出:

{"a":1,"b":10}