在 Shell 脚本中遍历 JSON 数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33950596/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 18:10:13  来源:igfitidea点击:

Iterating through JSON array in Shell script

jsonbashjq

提问by kosta

I have a JSON data as follows in data.json file

我在 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"}
]

I want to iterate through the array and extract the value for each element in a loop. I saw jq. I find it difficult to use it to iterate. How can I do that?

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

回答by Jeff Mercado

Just use a filter that would return each item in the array. Then loop over the results, just make sure you use the compact output option (-c) so each result is put on a single line and is treated as one item in the loop.

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

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

回答by touchStone

Try Build it around this example. (Source: Original Site)

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

Example:

例子:

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]

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

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

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

回答by peak

An earlier answer in this thread suggested using jq's foreach, but that may be much more complicated than needed, especially given the stated task. Specifically, foreach(and reduce) are intended for certain cases where you need to accumulate results.

该线程中较早的答案建议使用 jq's foreach,但这可能比需要的复杂得多,尤其是考虑到规定的任务。具体来说,foreach(和reduce) 适用于您需要累积结果的某些情况。

In many cases (including some cases where eventually a reduction step is necessary), it's better to use .[]or map(_). The latter is just another way of writing [.[] | _] so if you are going to use jq, it's really useful to understand that .[] simply creates a streamof values. For example, [1,2,3] | .[]produces a stream of the three values.

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

To take a simple map-reduce example, suppose you want to find the maximum length of an array of strings. One solution would be [ .[] | length] | max.

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

回答by Mashmagar

jqhas a shell formatting option: @sh.

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

You can use the following to format your json data as shell parameters:

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

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

The output will look like:

输出将如下所示:

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

To process each row, we need to do a couple of things:

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

  • Set the bash for-loop to read the entire row, rather than stopping at the first space (default behavior).
  • Strip the enclosing double-quotes off of each row, so each value can be passed as a parameter to the function which processes each row.
  • 将 bash for 循环设置为读取整行,而不是在第一个空格处停止(默认行为)。
  • 去掉每一行的封闭双引号,因此每个值都可以作为参数传递给处理每一行的函数。

To read the entire row on each iteration of the bash for-loop, set the IFSvariable, as described in this answer.

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

To strip off the double-quotes, we'll run it through the bash shell interpreter using xargs:

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

stripped=$(echo $original | xargs echo)


Putting it all together, we have:

综合起来,我们有:

#!/bin/bash

function processRow() {
  original_name=
  changed_name=

  # 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