我用 jq 解析了一个 json 文件,如下所示:
# cat test.json | jq '.logs' | jq '.[]' | jq '._id' | jq -s
Run Code Online (Sandbox Code Playgroud)
它返回一个这样的数组: [34,235,436,546,.....]
使用 bash 脚本我描述了一个数组:
# declare -a msgIds = ...
Run Code Online (Sandbox Code Playgroud)
当我将上面给出的数组传递给这个数组时,这个数组使用()而不是[]so 它将不起作用。
([324,32,45..])这会导致问题。如果我删除jq -s,则会形成一个只有 1 个成员的数组。
有没有办法解决这个问题?
Gri*_*vit 12
要正确解析可能包含换行符(以及任何其他任意(非 NUL)字符)的值,请使用 jq 的@sh过滤器生成以空格分隔的带引号的字符串,并使用 Bash 的过滤器declare -a将带引号的字符串解析为数组元素。(无需预处理)
foo.json:
{"data": ["$0", " \t\n", "*", "\"", ""]}
Run Code Online (Sandbox Code Playgroud)
str=$(jq -r '.data | @sh' foo.json)
declare -a arr="($str)" # must be quoted like this
Run Code Online (Sandbox Code Playgroud)
declare -p arr
# declare -a arr=([0]="\$0" [1]=$' \t\n' [2]="*" [3]="\"" [4]="")
Run Code Online (Sandbox Code Playgroud)
jq1.7(2023-09)从版本1.7开始,jq有一个--raw-output0选项,使其能够输出以 null 结尾的字符串,这些字符串可以像平常一样读入数组:
mapfile -d '' arr < <(jq --raw-output0 '.data[]' foo.json)
wait "$!" # use in bash-4.4+ to get exit status of the process substitution
Run Code Online (Sandbox Code Playgroud)
JSON 字符串可以包含 NUL 字符,而 shell 变量则不能。如果您的 JSON 输入可能包含 NUL,您可能需要添加一些特殊处理。
使用@sh过滤器时,JSON 字符串中的 NUL 字符将被静默替换为序列\0。请注意,这使得 JSON 字符串"\\0"无法"\u0000"区分。
使用该--raw-output0选项时,NUL 字符将触发错误并jq以退出状态 5 终止。
可以将过滤@sh器结合起来,--raw-output0一次可靠地读取多个数组(或单个嵌套数组),因为它将生成一个以 NUL 分隔的空格分隔的带引号字符串列表。
json='[[1,2],[3,4]]' i=0
while read -r -d ''; do
declare -a "arr$((i++))=($REPLY)"
done < <(jq --raw-output0 '.[]|@sh' <<<$json)
Run Code Online (Sandbox Code Playgroud)
for ((n=0; n<i; n++)); { declare -p "arr$n"; }
# declare -a arr0=([0]="1" [1]="2")
# declare -a arr1=([0]="3" [1]="4")
Run Code Online (Sandbox Code Playgroud)
Din*_*lam 10
我们可以通过两种方式解决这个问题。他们是:
输入字符串:
// test.json
{
"keys": ["key1","key2","key3"]
}
Run Code Online (Sandbox Code Playgroud)
方法一:
1) 使用jq -r(输出原始字符串,而不是 JSON 文本)。
KEYS=$(jq -r '.keys' test.json)
echo $KEYS
# Output: [ "key1", "key2", "key3" ]
Run Code Online (Sandbox Code Playgroud)
2)使用@sh(将输入字符串转换为一系列以空格分隔的字符串)。它从字符串中删除方括号[]、逗号(,)。
KEYS=$(<test.json jq -r '.keys | @sh')
echo $KEYS
# Output: 'key1' 'key2' 'key3'
Run Code Online (Sandbox Code Playgroud)
3)tr用于从字符串输出中删除单引号。要删除特定字符,请使用tr.
KEYS=$((<test.json jq -r '.keys | @sh')| tr -d \')
echo $KEYS
# Output: key1 key2 key3
Run Code Online (Sandbox Code Playgroud)
4)我们可以通过将字符串输出放在圆括号()中来将逗号分隔的字符串转换为数组。它也称为复合赋值,我们用一堆值声明数组。
ARRAYNAME=(value1 value2 .... valueN)
Run Code Online (Sandbox Code Playgroud)
#!/bin/bash
KEYS=($((<test.json jq -r '.keys | @sh') | tr -d \'\"))
echo "Array size: " ${#KEYS[@]}
echo "Array elements: "${KEYS[@]}
# Output:
# Array size: 3
# Array elements: key1 key2 key3
Run Code Online (Sandbox Code Playgroud)
方法二:
1)jq -r用于获取字符串输出,然后用于tr删除方括号、双引号和逗号等字符。
#!/bin/bash
KEYS=$(jq -r '.keys' test.json | tr -d '[],"')
echo $KEYS
# Output: key1 key2 key3
Run Code Online (Sandbox Code Playgroud)
2)然后我们可以通过将我们的字符串输出放在圆括号()中来将逗号分隔的字符串转换为数组。
#!/bin/bash
KEYS=($(jq -r '.keys' test.json | tr -d '[]," '))
echo "Array size: " ${#KEYS[@]}
echo "Array elements: "${KEYS[@]}
# Output:
# Array size: 3
# Array elements: key1 key2 key3
Run Code Online (Sandbox Code Playgroud)
使用jq -r输出字符串“原材料”,没有JSON格式,并使用@sh格式来格式化你的结果作为外壳消费的字符串。根据 jq 文档:
@sh:
输入已转义,适用于 POSIX shell 的命令行。如果输入是数组,则输出将是一系列以空格分隔的字符串。
所以可以做例如
msgids=($(<test.json jq -r '.logs[]._id | @sh'))
Run Code Online (Sandbox Code Playgroud)
并得到你想要的结果。
来自 jq 常见问题解答(https://github.com/stedolan/jq/wiki/FAQ):
:如何将 jq 生成的 JSON 文本流转换为相应值的 bash 数组?
答:一种选择是使用映射文件(又名 readarray),例如:
mapfile -t array <<< $(jq -c '.[]' input.json)
Run Code Online (Sandbox Code Playgroud)
另一种可能指示在其他 shell 中执行的操作的替代方法是在 while 循环中使用 read -r。以下 bash 脚本使用 JSON 文本填充数组 x。关键点是 -c 选项的使用,以及 bash 习惯用法的使用while read -r value; do ... done < <(jq .......):
#!/bin/bash
x=()
while read -r value
do
x+=("$value")
done < <(jq -c '.[]' input.json)
Run Code Online (Sandbox Code Playgroud)