jq如何获取所有值并用于脚本参数

时间:2016-02-01 22:20:48

标签: json jq

我有这个vms.json

[
    {
        "name": "jms1",
        "port1": 24000,
        "port2": 25000,
        "port3": 26000
    },

    {
        "name": "jms2",
        "port1": 24001,
        "port2": 25000,
        "port3": 26001
    }
]

我有一个port_script.sh [name] [port1] [port2] [port3]作为编号参数。

我可以运行这个jq来获取密钥,但我需要获取值。

jq -r -c '.[] |keys' vms.json
["port1","name","port2","port3"]
["port1","name","port2","port3"]

我不知道如何使用此输出来获取关联的值。 如果我能得到值,我应该能够通过xargs将它们传递给我的脚本。

提前感谢您的帮助

添加:port_script.sh

#!/bin/bash
name=$1
port1=$2
port2=$3
port3=$4
vagrant ssh ${name} -- \
    -L ${port1}:127.0.0.1:${port1}  \
    -R ${port2}:127.0.0.1:${port2}  \
    -L ${port3}:127.0.0.1:${port3} 

应用Santiago和Peak的回复 - 这对我有用

eval "$(jq -r '.[] | ["./port_script.sh"] + [.name, .port1, .port2, .port3 | @sh] | join(" ")' vms.json)"

4 个答案:

答案 0 :(得分:2)

让圣地亚哥的答案更进一步,你可以写下:

$ jq -r '.[] | "port_script.sh \"\(.name)\" \"\(.port1)\" \"\(.port2)\" \"\(.port3)\""'

根据您的输入,这会产生:

port_script.sh "jms1" "24000" "25000" "26000"
port_script.sh "jms2" "24001" "25000" "26001"

或者更好或许:

$ jq -r --arg command port_script.sh '.[] 
  | $command + " \"\(.name)\" \"\(.port1)\" \"\(.port2)\" \"\(.port3)\""'

如果每个对象中的键都是脚本所需的顺序,那么我们可以进一步概括一步,以便jq脚本适用于任意数量的键:

jq -nr --arg command port_script.sh '
  .[] | $command + " " + ([.[]] | @sh)'

port_script.sh 'jms1' 24000 25000 26000
port_script.sh 'jms2' 24001 25000 26001

(不幸的是,jq没有system子命令,至少现在还没有。)

答案 1 :(得分:1)

您尝试尝试的内容目前尚不清楚,但这里有一些可能有用的指示:

要获取脚本所需的值,只需使用.foo语法引用它们即可。例如,在给定输入文件上运行jq -r '.[].name'将产生以下输出:

jms1
jms2

同样,你可以参考所有这些:

jq -r '.[] | .name, .port1, .port2, .port3'

jms1
24000
25000
26000
jms2
24001
25000
26001

而且,如果您在数组中喜欢它们,如上例所示,只需将它们用括号括起来:

jq -r -c '.[] | [.name, .port1, .port2, .port3]'

["jms1", 24000, 25000, 26000]
["jms2", 24001, 25000, 26001]

希望这有帮助!在没有真正理解你的问题的情况下,我可以去。

答案 2 :(得分:0)

最近我不得不处理这个问题,因为我被要求在shell脚本中使用json。

因此,对于将来找到此主题的任何人:

我建议不要使用eval函数,而建议使用更原生的shell方法。

考虑使用循环和读取命令。

#!/bin/bash
read -d '' JSON <<'EOF' || true
[
    {
        "name": "jms1",
        "port1": 24000,
        "port2": 25000,
        "port3": 26000
    },

    {
        "name": "jms2",
        "port1": 24001,
        "port2": 25000,
        "port3": 26001
    }
]
EOF

while IFS=$'\t' read name port1 port2 port3 eol ; do

    ./port_script.sh "$name" "$port1" "$port2" "$port3"

done <<<" $(echo "$JSON" | jq --raw-output '.[] | [.name, .port1, .port2, .port3] | @tsv' )"

注意:

如果通过设计,您的JSON可能包含空字段,则可能是一个问题。 jq的@tsv函数可以正常工作,并用制表符分隔所有内容。但是至少Bash会将多个定界符视为一个。仅当您使用空格(“”或“ \ t”)作为分隔符时才如此。我通过使用以下方法来解决此问题:

$(echo "$JSON" | jq --raw-output '.[] | [.name, .port1, .port2, .port3] | @tsv' | tr $'\011' $'\037' )  

这将用ASCII单位分隔符(八进制037)替换所有选项卡(八进制011)。

我首先尝试仅将'\ t \ t'替换为'\ t [space] \ t',因为当您将其用作port_script.sh的参数时,多个空格将再次减少为1,因此效果很好。 ..但这会抛出任何条件测试(例如test -z)。

单元分隔符应该可以安全地用于此目的。如果jq可以直接实现它,那就太好了。。。。

还要在while循环中更改它:

...
while IFS=$'\037' read name port1 port2 port3 eol ; do
...

答案 3 :(得分:-2)

我在JavaScript中知道你可以做到这一点

array.forEach(function(a) {
     console.log(Object.keys(a));
});

Object.keys特别方便,因为它可以让你获得一个对象的键。然后迭代一个数组并登录到控制台

https://jsfiddle.net/f8rbdn85/