[英]Pipe multiple jq values to “while read -r” loop
我正在尝试找到一种干净的方法,在 while 循环中将 2 个 json 字符串值分配给 2 个变量。 我正在使用的循环和输入如下。
输入:
foo='
[
{
"name":"name string (more info)",
"nested_name":{
"name":"my name",
"conclusion":"failure",
"number":11
}
},
{
"name":"name string (more info)",
"nested_name":{
"name":"my other name",
"conclusion":"failure",
"number":13
}
}
]'
目前我有以下几点:
echo "$foo" | jq ".[].name,.[].nested_name.name" | while read -r foo bar; do
# do stuff with foo and bar
done
在迭代 1 中,我想要:
foo = "name string (more info)"
bar = "my name"
迭代 2:
foo = "name string (more info)"
bar = "my other name"
但是,这会生成以下不正确的输出:
foo = "name
bar = string (more info)"
foo = "name
bar = string (more info)"
foo = "my
bar = name"
foo = "my
bar = other name"
我整天都在这,任何意见或建议将不胜感激!
使用两个read
,每行一个:
#!/usr/bin/env bash
json='
[
{
"name":"name string (more info)",
"nested_name":{
"name":"my name",
"conclusion":"failure",
"number":11
}
},
{
"name":"name string (more info)",
"nested_name":{
"name":"my other name",
"conclusion":"failure",
"number":13
}
}
]'
while read -r foo && read -r bar; do
printf "foo=%s\nbar=%s\n" "$foo" "$bar"
done < <(jq ".[] | .name, .nested_name.name" <<<"$json")
我不得不改变你的jq
表达式以获得你想要的输出。
还要注意对原始 JSON 文本和循环变量使用不同的名称,使用here 字符串而不是echo
,并使用文件重定向而不是管道; 如果while
的主体设置了以后需要的任何变量, while
很有用。
将所有jq
输出读入数组然后对其进行迭代的替代方法:
readarray -t lines < <(jq ".[] | .name, .nested_name.name" <<<"$json")
for (( i = 0; i < ${#lines[@]}; i += 2 )); do
foo=${lines[i]}
bar=${lines[i+1]}
printf "foo=%s\nbar=%s\n" "$foo" "$bar"
done
如果我模拟一些“CSV 输入”,我可以这样做:(注意IFS
设置为,
)
echo 'aaa,bbb\nccc,ddd' | while IFS=, read -r x y; do
echo "x=$x, y=$y"
done
输出:
x=aaa, y=bbb
x=ccc, y=ddd
您可以使用以下jq
命令生成类似的“CSV 输出”:
jq --raw-output '.[] | "\(.name),\(.nested_name.name)"'
所以我认为它看起来像这样:
echo "$foo" | jq --raw-output '.[] | "\(.name),\(.nested_name.name)"' | while IFS=, read -r foo bar; do
# do stuff with foo and bar
done
这个怎么样: https : //jqplay.org/s/4MPWmMjFmM
assuming foobar.json
jq -r '.[] | "foo=\"" + .name + "\"","bar=\"" + .nested_name.name + "\""' foobar.json
foo="name string (more info)"
bar="my name"
foo="name string (more info)"
bar="my other name"
我更喜欢这样做:
jq --argjson foo "$foo" --null-input --compact-output '$foo[]' | while IFS= read -r item
do
name="$(jq --argjson item "$item" --null-input --raw-output '$item.name')"
nested_name="$(jq --argjson item "$item" --null-input --raw-output '$item.nested_name.name')"
printf 'name is "%s" and nested_name is "%s"\n' "$name" "$nested_name"
done
虽然此方法涉及对jq
额外调用,但它有几个好处:
如果您希望它更简洁,那么使用缩写选项也是如此。
jq --argjson foo "$foo" -nc '$foo[]' | while IFS= read -r item
do
name="$(jq --argjson item "$item" -nr '$item.name')"
nested_name="$(jq --argjson item "$item" -nr '$item.nested_name.name')"
printf 'name is "%s" and nested_name is "%s"\n' "$name" "$nested_name"
done
更详细一点:
--argjson
将我们的 JSON 字符串作为单个参数--null-input
并使用--null-input
忽略标准输入。 这样我们就不必担心传入过程中的转义或分隔符。--compact-output
(或-c
)每行输出一个 JSON 对象。IFS=
来确保我们的 JSON 字符串中的空格和制表符不会被当作分隔符。 只有换行符将用作分隔符,并且因为 JSON 字符串中的所有换行符都必须被转义,所以我们可以确信对于原始 JSON 数组中的每个项目,我们将只循环一次。--raw-output
(或-r
)将 JSON 字符串的值直接输出到 shell 变量中。 (如果我们想要 JSON 编码的字符串,我们可以选择省略它。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.