将一个JSON数组转换为一个字符串bash数组

32
我该如何将一个包含多个对象的 JSON 数组解析为 Bash 数组,并将这些对象作为字符串存储在 Bash 数组中?
我正在尝试执行以下操作:
CONVO=$(get_json_array | jq '.[]')
for CONVERSATION in $CONVERSATIONS
do
    echo "${CONVERSATION}"
done

但是回声会输出行而不是特定的对象。 对象的格式如下:

{ "key1":"value1", "key2": "value2"}

我需要将它传递给一个API:

api_call '{ "key1":"value1", "key2": "value2"}'

请参考 https://unix.stackexchange.com/a/630274/42620 中的方法将 JSON 数组转换为 Bash 数组,然后使用普通的 Shell 循环。 - jrw32982
5个回答

58
问题在于jq仍然只是输出文本行;即使你不能保留每个数组元素作为单个单位。尽管如此,只要换行符不是任何对象的有效字符,您仍然可以将每个对象单独输出在一行上。
get_json_array | jq -c '.[]' | while read object; do
    api_call "$object"
done

在这种情况下,您可以使用bash 4中的readarray命令来构建一个数组:

readarray -t conversations < <(get_json_array | jq -c '.[]')
for conversation in "${conversations[@]}"; do
    api_call "$conversation"
done

+1. 回复:“只要换行符不是任何对象的有效字符”:由于这些是JSON对象,所以这不是一个问题。 - ruakh
啊,我曾经错误地认为换行符可以出现在哈希值中,但看起来它们必须被编码为“\n”。 - chepner
2
如果您使用jq -j而不是jq -r,JQ本身不会添加分隔符,因此您可以从代码中添加自己的分隔符(例如NUL文字)。 - Charles Duffy
2
只想指出迭代变量在循环头和循环体中必须叫相同的名字(conversion vs. conversation)。因为改动只有 2 个字符,无法改进答案,而 StackOverflow 要求至少改变 6 个字符。 - marcelbrueckner

2
这是一个没有循环的解决方案:
json=$(jq -c ".my_key[]"  ./my-file.json)
json_without_quotes=$(echo ${json//\"/""})
declare -a all_apps_array=($(echo $json_without_quotes | tr "\n" " "))

3
你可以使用 jq -r 替换第二行,它会打印原始的 JSON(丢弃引号)。 - no more sigsegv
2
如果有空格,它就无法工作。 - I wrestled a bear once.
一个简洁的解决方案是 declare -a all_apps_array =($(jq -r ". my_key[]" ./my-file.json | tr "\n" " ")) - nish-ant

1
这个方法的功劳归功于@ingernet。不需要使用jq。这里使用sed删除[],,并在它们之间留下一个空格,以便可以用()包裹。
newArray=( $(echo $jsonArrayString | sed -e 's/\[//g' -e 's/\]//g' -e 's/\,/ /g') );

这个程序有严重的漏洞。如果你的字符串是“foo * bar”,那么*将被替换为文件名列表,而这只是我想到的许多问题中的第一个。 - Charles Duffy

0

还有一种选项,无需循环。

jq -c ".response[]"  "${file}" | sed 's/[{|}]//g' | tr ',' '\n' | sed 's/"//g' | awk -F":" '{print toupper($1)":"$2}'

希望能对某人有所帮助


0

这应该将一个json数组转换为bash数组,而不考虑json条目的内容。我需要它将文件列表传递给github操作中的linter。重要的是进行单个调用以获得所需的输出,而不是每个文件进行一次调用。它在bash 3.2中运行。

count=$(jq length <<< "$pr_files")
declare -a files=()
for (( i=0; i < count; i++ ))
do
    file=$(jq -r ".[$i]" <<< "$pr_files")
    files+=( "$file" )
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接