我有一个 JSON 输出,其中包含存储在变量中的对象列表。 (我的表述可能不太对)
[
{
"item1": "value1",
"item2": "value2",
"sub items": [
{
"subitem": "subvalue"
}
]
},
{
"item1": "value1_2",
"item2": "value2_2",
"sub items_2": [
{
"subitem_2": "subvalue_2"
}
]
}
]
我需要数组中 item2 的所有值才能在 ubuntu 14.04.1 上运行 bash 脚本。
我找到了很多方法将整个结果放入数组中,而不仅仅是我需要的项目
答案1
使用杰克:
readarray arr < <(jq '.[].item2' json)
printf '%s\n' "${arr[@]}"
如果您需要更强化的方法:
readarray -td '' arr
对于带有换行符或其他特殊字符的输入,避免分词。
输出:
value2
value2_2
查看:
处理替换>(command ...)
或被<(...)
临时文件名替换。写入或读取该文件会导致字节通过管道传输到内部命令。通常与文件重定向结合使用:cmd1 2> >(cmd2)
.看http://mywiki.wooledge.org/ProcessSubstitution http://mywiki.wooledge.org/BashFAQ/024
答案2
以下实际上是错误的:
# BAD: Output line of * is replaced with list of local files; can't deal with whitespace
arr=( $( curl -k "$url" | jq -r '.[].item2' ) )
如果您有 bash 4.4 或更高版本,则可以使用最佳选项:
# BEST: Supports bash 4.4+, with failure detection and newlines in data
{ readarray -t -d '' arr && wait "$!"; } < <(
set -o pipefail
curl --fail -k "$url" | jq -j '.[].item2 | (., "\u0000")'
)
...而使用 bash 4.0,您可以以失败检测和字面换行符支持为代价获得简洁性:
# OK (with bash 4.0), but can't detect failure and doesn't support values with newlines
readarray -t arr < <(curl -k "$url" | jq -r '.[].item2' )
...或 bash 3.x 兼容性和故障检测,但没有换行符支持:
# OK: Supports bash 3.x; no support for newlines in values, but can detect failures
IFS=$'\n' read -r -d '' -a arr < <(
set -o pipefail
curl --fail -k "$url" | jq -r '.[].item2' && printf '\0'
)
...或 bash 3.x 兼容性和换行符支持,但没有故障检测:
# OK: Supports bash 3.x and supports newlines in values; does not detect failures
arr=( )
while IFS= read -r -d '' item; do
arr+=( "$item" )
done < <(curl --fail -k "$url" | jq -j '.[] | (.item2, "\u0000")')
答案3
用于jq
生成您评估的 shell 语句:
eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"
给定问题中的 JSON 文档,调用jq
将生成字符串
arr=( 'value2' 'value2_2' )
然后由您的 shell 对其进行评估。计算该字符串将创建arr
包含两个元素value2
和 的命名数组value2_2
:
$ eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"
$ printf '"%s"\n' "${arr[@]}"
"value2"
"value2_2"
运算符@sh
injq
会注意正确引用 shell 的数据。
或者,将该arr=( ... )
部分移出表达式jq
:
eval "arr=( $( jq -r '@sh "\([.[].item2])"' file.json ) )"
现在,jq
仅生成引用的元素列表,然后将其插入arr=( ... )
并求值。
如果需要从curl
命令中读取数据,请在上面的命令中使用curl ... | jq -r ...
代替。jq -r ... file.json
答案4
感谢 sputnick,我得到了这个:
arr=( $(curl -k https://localhost/api | jq -r '.[].item2') )
我的 JSON 是 API 的输出。我所需要做的就是删除文件参数并将|
curl 的输出通过管道传输到jq。效果很好,节省了一些步骤。