在Shell脚本中迭代JSON数组

kos*_*sta 16 bash json jq

我在data.json文件中有如下JSON数据

[
  {"original_name":"pdf_convert","changed_name":"pdf_convert_1"},
  {"original_name":"video_encode","changed_name":"video_encode_1"},
  {"original_name":"video_transcode","changed_name":"video_transcode_1"}
]
Run Code Online (Sandbox Code Playgroud)

我想迭代数组并提取循环中每个元素的值.我看到了jq.我发现很难用它来迭代.我怎样才能做到这一点?

Jef*_*ado 31

只需使用一个过滤器,它将返回数组中的每个项目.然后遍历结果,只需确保使用紧凑输出选项(-c),这样每个结果都放在一行上,并被视为循环中的一个项目.

jq -c '.[]' input.json | while read i; do
    # do stuff with $i
done
Run Code Online (Sandbox Code Playgroud)

  • jq 输出一个流,因此您不会逐行或逐项进行。 (3认同)
  • `for`循环遍历以空格分隔的单词,而不是行. (2认同)
  • 如果你的输出包含空格,你需要将 IFS 设置为换行符,例如使用 Bash `IFS=$'\n'`。 (2认同)

fel*_*crs 27

通过利用 Bash 数组的强大功能,您可以执行以下操作:

# read each item in the JSON array to an item in the Bash array
readarray -t my_array < <(jq --compact-output '.[]' input.json)

# iterate through the Bash array
for item in "${my_array[@]}"; do
  original_name=$(jq --raw-output '.original_name' <<< "$item")
  changed_name=$(jq --raw-output '.changed_name' <<< "$item")
  # do your stuff
done
Run Code Online (Sandbox Code Playgroud)

  • “Bash 数组的威力!⚡️”- 实在是太厉害了。 (14认同)
  • macOS 用户请注意 - 这不会“开箱即用”,因为苹果由于许可而坚持使用旧版本的 bash(当前为 v3.2.57)。您可以使用 homebrew 来获取最新版本。您需要将较新的版本设置为默认 shell 或将脚本设置为通过 shebang 显式使用它 (4认同)
  • 如果从变量读取:`readarray -t my_array &lt; &lt;(jq -c '.[]' &lt;&lt;&lt; $input_json)` (3认同)
  • 这是唯一可以开箱即用的解决方案。所有其他的都是需要认真纠正才能发挥作用的概念! (2认同)

Tid*_*oni 17

来自迭代 bash 中的日期的 json 数组(有空格)

items=$(echo "$JSON_Content" | jq -c -r '.[]')
for item in ${items[@]}; do
    echo $item
    # whatever you are trying to do ...
done
Run Code Online (Sandbox Code Playgroud)


Mas*_*gar 12

jq有一个 shell 格式化选项:@sh.

您可以使用以下内容将 json 数据格式化为 shell 参数:

cat data.json | jq '. | map([.original_name, .changed_name])' | jq @sh
Run Code Online (Sandbox Code Playgroud)

输出将如下所示:

"'pdf_convert' 'pdf_convert_1'"
"'video_encode' 'video_encode_1'",
"'video_transcode' 'video_transcode_1'"
Run Code Online (Sandbox Code Playgroud)

要处理每一行,我们需要做几件事:

  • 将 bash for 循环设置为读取整行,而不是在第一个空格处停止(默认行为)。
  • 去掉每一行的封闭双引号,这样每个值都可以作为参数传递给处理每一行的函数。

要在 bash for 循环的每次迭代中读取整行,请设置IFS变量,如本答案中所述

为了去掉双引号,我们将使用 bash shell 解释器运行它xargs

stripped=$(echo $original | xargs echo)
Run Code Online (Sandbox Code Playgroud)

综合起来,我们有:

#!/bin/bash

function processRow() {
  original_name=$1
  changed_name=$2

  # TODO
}

IFS=$'\n' # Each iteration of the for loop should read until we find an end-of-line
for row in $(cat data.json | jq '. | map([.original_name, .changed_name])' | jq @sh)
do
  # Run the row through the shell interpreter to remove enclosing double-quotes
  stripped=$(echo $row | xargs echo)

  # Call our function to process the row
  # eval must be used to interpret the spaces in $stripped as separating arguments
  eval processRow $stripped
done
unset IFS # Return IFS to its original value
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用 `--raw-output` 或 `-r` 标志来排除封闭的双引号,而不必“剥离封闭的双引号”,用 `jq -r @sh` 替换 `jq @sh` (7认同)
  • 您(当前)不需要通过第二个 jq 的 shell 管道;只需附加`|就可以很好地工作 jq 管道中的@sh`。如“jq -r”。| 地图(废话)| @sh'` (2认同)

tou*_*one 2

尝试围绕这个示例构建它。(来源:原站)

例子:

jq '[foreach .[] as $item ([[],[]]; if $item == null then [[],.[0]]     else [(.[0] + [$item]),[]] end; if $item == null then .[1] else empty end)]'
Run Code Online (Sandbox Code Playgroud)

Input [1,2,3,4,null,"a","b",null]

Output [[1,2,3,4],["a","b"]]