jq 如何获取所有值并用于脚本参数
jq how to grab all values and use for script arguments
我有这个vms.json
[
{
"name": "jms1",
"port1": 24000,
"port2": 25000,
"port3": 26000
},
{
"name": "jms2",
"port1": 24001,
"port2": 25000,
"port3": 26001
}
]
我有一个 port_script.sh
[名称] [端口 1] [端口 2] [端口 3] 作为编号参数。
我可以 运行 这个 jq 来获取键,但我需要获取值。
jq -r -c '.[] |keys' vms.json
["port1","name","port2","port3"]
["port1","name","port2","port3"]
我不知道如何使用此输出来获取关联值。
如果我可以获得这些值,我应该能够通过 xargs 将它们通过管道传输到我的脚本中。
在此先感谢您的帮助
已添加:port_script.sh
#!/bin/bash
name=
port1=
port2=
port3=
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)"
我知道 JavaScript 你可以做到这一点
array.forEach(function(a) {
console.log(Object.keys(a));
});
Object.keys 特别方便,因为它可以让您获取对象的键。然后只需遍历一个数组并登录到控制台
您尝试尝试的内容非常不清楚,但这里有一些可能有用的指示:
要获取脚本所需的值,只需使用 .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]
希望这对您有所帮助!这是我在没有真正理解你的问题的情况下所能做到的。
将圣地亚哥的回答更进一步,您可以这样写:
$ 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
子命令,至少现在没有。)
我最近不得不处理这个问题,因为我被要求在 shell 脚本中使用 json。
因此对于以后发现此主题的任何人:
我建议使用更原生的 shell 方法而不是使用 eval 函数。
考虑使用循环和读取命令。
#!/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 会将多个分隔符视为一个分隔符。仅当您使用 whitespaces(" " 或 "\t")作为分隔符时才会出现这种情况。我使用以下方法解决了这个问题:
$(echo "$JSON" | jq --raw-output '.[] | [.name, .port1, .port2, .port3] | @tsv' | tr $'1' $'7' )
这会将所有制表符(八进制 011)替换为 ASCII 单位分隔符(八进制 037)。
我首先尝试将“\t\t”替换为“\t[space]\t”,这样可以正常工作,因为多个 space 将再次减少为一个当您将它们用作 port_script.sh 的参数时...但这会抛出任何条件测试(例如测试 -z)。
为此使用单位分隔符应该是安全的。如果 jq 可以直接实现这个就好了……但是是的:)
同时为您的 while 循环更改此设置:
...
while IFS=$'7' read name port1 port2 port3 eol ; do
...
我有这个vms.json
[
{
"name": "jms1",
"port1": 24000,
"port2": 25000,
"port3": 26000
},
{
"name": "jms2",
"port1": 24001,
"port2": 25000,
"port3": 26001
}
]
我有一个 port_script.sh [名称] [端口 1] [端口 2] [端口 3] 作为编号参数。
我可以 运行 这个 jq 来获取键,但我需要获取值。
jq -r -c '.[] |keys' vms.json
["port1","name","port2","port3"]
["port1","name","port2","port3"]
我不知道如何使用此输出来获取关联值。 如果我可以获得这些值,我应该能够通过 xargs 将它们通过管道传输到我的脚本中。
在此先感谢您的帮助
已添加:port_script.sh
#!/bin/bash
name=
port1=
port2=
port3=
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)"
我知道 JavaScript 你可以做到这一点
array.forEach(function(a) {
console.log(Object.keys(a));
});
Object.keys 特别方便,因为它可以让您获取对象的键。然后只需遍历一个数组并登录到控制台
您尝试尝试的内容非常不清楚,但这里有一些可能有用的指示:
要获取脚本所需的值,只需使用 .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]
希望这对您有所帮助!这是我在没有真正理解你的问题的情况下所能做到的。
将圣地亚哥的回答更进一步,您可以这样写:
$ 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
子命令,至少现在没有。)
我最近不得不处理这个问题,因为我被要求在 shell 脚本中使用 json。
因此对于以后发现此主题的任何人:
我建议使用更原生的 shell 方法而不是使用 eval 函数。
考虑使用循环和读取命令。
#!/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 会将多个分隔符视为一个分隔符。仅当您使用 whitespaces(" " 或 "\t")作为分隔符时才会出现这种情况。我使用以下方法解决了这个问题:
$(echo "$JSON" | jq --raw-output '.[] | [.name, .port1, .port2, .port3] | @tsv' | tr $'1' $'7' )
这会将所有制表符(八进制 011)替换为 ASCII 单位分隔符(八进制 037)。
我首先尝试将“\t\t”替换为“\t[space]\t”,这样可以正常工作,因为多个 space 将再次减少为一个当您将它们用作 port_script.sh 的参数时...但这会抛出任何条件测试(例如测试 -z)。
为此使用单位分隔符应该是安全的。如果 jq 可以直接实现这个就好了……但是是的:)
同时为您的 while 循环更改此设置:
...
while IFS=$'7' read name port1 port2 port3 eol ; do
...