如何使用 jq 将信息返回到 shell,同时考虑到空格?

如何使用 jq 将信息返回到 shell,同时考虑到空格?

给定这个文件:

$ cat fruits.json
[
  { "name": "apple" },
  { "name": "banana\nfofanna" },
  { "name": "my kiwi" }
]

如何使用它jq来检索 shell 用作数据的水果名称列表,例如填充数组?

相当于fruits下面数组的赋值:

$ fruits=( 
'apple'
'banana
fofanna'
'my kiwi'
)
$ for f in "${fruits[@]}" ;do echo "<$f>"; done
<apple>
<banana
fofanna>
<my kiwi>

以下均无效:

$ fruits=( $(jq -r ' .[].name       ' fruits.json))
$ fruits=( $(jq -r ' .[].name | @sh ' fruits.json))
$ fruits=( $(jq    ' .[].name | @sh ' fruits.json))

答案1

问题末尾的前两次尝试不起作用,因为它们依赖于 shell 分割jq空白的输出。由于换行符是一种空白,因此您会丢失数据中的换行符(以及制表符和原始空格)。

此外,这些尝试也无法引用字符串数据,因此如果任何字符串包含文件名通配符,您就会发生文件名通配符。

最后一次尝试由于类似的原因失败,但另外也没有正确解码数据,将编码的换行符留在原处。


使用内置运算符@shinjq引用数据并构建数组赋值:

eval "$( jq -r '"fruits=(" + (map(.name)|@sh) + ")"' fruits.json )"

对于给定的 JSON 数据,这将导致当前 shell 评估以下赋值,从而创建数组fruits

fruits=('apple' 'banana
fofanna' 'my kiwi')

在评估该声明后,

$ printf '<%s>\n' "${fruits[@]}"
<apple>
<banana
fofanna>
<my kiwi>

作为替代方案,以下内容将附加nameshell 数组中每个元素的值:

$ jq -r '"fruits+=(" + (.[].name | @sh) + ")"' fruits.json
fruits+=('apple')
fruits+=('banana
fofanna')
fruits+=('my kiwi')
$ unset -v fruits
$ eval "$(jq -r '"fruits+=(" + (.[].name | @sh) + ")"' fruits.json)"
$ printf '<%s>\n' "${fruits[@]}"
<apple>
<banana
fofanna>
<my kiwi>

答案2

你没有提到什么shell;对于 ZSH,人们可能会使用

% fru=( ${(fQg::)"$(jq '.[].name' ~/tmp/fru)"} )
% for f in $fru; printf '<%s>\n' $f
<apple>
<banana
fofanna>
<my kiwi>
% =echo -n "<${fru[2]}>" | od -bc
0000000   074 142 141 156 141 156 141 012 146 157 146 141 156 156 141 076
           <   b   a   n   a   n   a  \n   f   o   f   a   n   n   a   >
0000020

它执行jq调用,然后f将结果拆分为换行符,并删除输出在字符串上留下的Q引用,以及jqg:: 作用类似于内置回声来执行插值\n在输入中的字符串上。

答案3

基于 @Kusalananda、@roaima 和 @StéphaneChazelas 的回答和评论以及上面评论中提到的类似问题,我能够想出:

list=$( jq -r ' .[].name | @sh ' fruits.json ) || exit 1
eval "fruits=( $list )" || exit 1
printf "<%s>\n" "${fruits[@]}"

相关内容