在Shell脚本中迭代JSON数组

时间:2015-11-27 05:06:51

标签: json bash 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"}
]

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

4 个答案:

答案 0 :(得分:19)

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

jq -c '.[]' input.json | while read i; do
    # do stuff with $i
done

答案 1 :(得分:1)

尝试围绕此示例构建它。 (来源:原创网站)

示例:

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

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

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

答案 2 :(得分:1)

此线程中的早期答案建议使用jq&#39; <p> albumid <s:property value="idAlbum" /> <s:hidden name="idAlbum" /> </p> ,但这可能比需要的要复杂得多,特别是考虑到所述任务。具体而言,foreach(和foreach)适用于需要累积结果的特定情况。

在许多情况下(包括最终需要减少步骤的某些情况),使用reduce.[]会更好。后者只是另一种写作方式[。[] | _]所以如果你打算使用jq,理解它真的很有用。[]只是创建一个值的。 例如,map(_)生成三个值的流。

要采用简单的map-reduce示例,假设您要查找字符串数组的最大长度。一种解决方案是[1,2,3] | .[]

答案 3 :(得分:0)

jq具有外壳格式选项:@sh

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

cat data.json | jq '. | map([.original_name, .changed_name])' | jq @sh

输出将如下所示:

"'pdf_convert' 'pdf_convert_1'"
"'video_encode' 'video_encode_1'",
"'video_transcode' 'video_transcode_1'"

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

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

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

要去除双引号,我们将使用xargs通过bash shell解释器运行它:

stripped=$(echo $original | xargs echo)

将它们放在一起,我们有:

#!/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