【问题标题】:how to for loop a jq array result in shell script如何在shell脚本中循环一个jq数组结果
【发布时间】:2021-09-04 09:01:55
【问题描述】:

我有一个json数据如下

{
  "id": {
    "bioguide": "E000295",
    "thomas": "02283",
    "govtrack": 412667,
    "opensecrets": "N00035483",
    "lis": "S376"
  },
  "bio": {
    "gender": "F",
    "birthday": "1970-07-01"
  },
  "tooldatareports": [
    {
      "name": "A",
      "tooldata": [
        {
          "toolid": 12345,
          "data": [
            {
              "time": "2021-01-01",
              "value": 1
            },
            {
              "time": "2021-01-02",
              "value": 10
            },
            {
              "time": "2021-01-03",
              "value": 5
            }
          ]
        },
        {
          "toolid": 12346,
          "data": [
            {
              "time": "2021-01-01",
              "value": 10
            },
            {
              "time": "2021-01-02",
              "value": 100
            },
            {
              "time": "2021-01-03",
              "value": 50
            }
          ]
        }
      ]
    }
  ]
}

现在我可以使用下面的命令行来获取包含两个字典的列表, 每个字典都有一个键“数据”,值是一个列表,

cat data.json |jq -n --stream '[fromstream(inputs | (.[0] | index("data")) as $ix | select($ix) | .[0] |= .[$ix:])]'

我想在 shell 脚本中用循环打印每个字典

我的 except 在每个循环中都打印了一个字典,总共有 2 个字典

但它看起来像一个字符串

下面是我的shell脚本

array=$(cat ernst.json | jq -n --stream '[fromstream(inputs | (.[0] | index("data")) as $ix | select($ix) | .[0] |= .[$ix:])]')

for d in $array
do
    echo $d
done

有人知道吗?

【问题讨论】:

    标签: json linux shell jq


    【解决方案1】:
    $ jq -cn --stream '[fromstream(inputs | (.[0] | index("data")) as $ix | select($ix) | .[0] |= .[$ix:])][]' data.json | while read d; do echo "item: $d"; done
    item: {"data":[{"time":"2021-01-01","value":1},{"time":"2021-01-02","value":10},{"time":"2021-01-03","value":5}]}
    item: {"data":[{"time":"2021-01-01","value":10},{"time":"2021-01-02","value":100},{"time":"2021-01-03","value":50}]}
    

    请注意,您可以使用更简单的jq 获得非常相似的输出:

    jq -c '.tooldatareports[].tooldata[].data' data.json  | while read d; do echo "item: $d"; done
    item: [{"time":"2021-01-01","value":1},{"time":"2021-01-02","value":10},{"time":"2021-01-03","value":5}]
    item: [{"time":"2021-01-01","value":10},{"time":"2021-01-02","value":100},{"time":"2021-01-03","value":50}]
    

    您可以通过以下方式获得相同的输出(这似乎是不必要的):

    $ jq -c '.tooldatareports[].tooldata[].data | {"data": .}' data.json  | while read d; do echo "item: $d"; done
    item: {"data":[{"time":"2021-01-01","value":1},{"time":"2021-01-02","value":10},{"time":"2021-01-03","value":5}]}
    item: {"data":[{"time":"2021-01-01","value":10},{"time":"2021-01-02","value":100},{"time":"2021-01-03","value":50}]}
    

    【讨论】:

    • 不错的方法,但我需要使用 --stream 标志,因为我的最终目标文件很大
    【解决方案2】:

    您的输出是一个 json 列表,因此您不会在它上面直接使用 bash 循环。 bash 循环不知道如何处理方括号,并将使用每个空格和换行符作为分隔符。再次使用jq 从您的 json 列表中获取单独的对象。这是通过jq -c '.[]' 完成的:

    array=$(cat data.json |jq -n --stream '[fromstream(inputs | (.[0] | index("data")) as $ix | select($ix) | .[0] |= .[$ix:])]' | jq -c '.[]')
    

    现在您有两个单独的行中的两个对象并且没有空格(-c = 紧凑输出),您可以在 bash 中循环它们:

    for d in $array
    do
        echo "$d"
        # whatever else you need to do with them
    done
    
    {"data":[{"time":"2021-01-01","value":1},{"time":"2021-01-02","value":10},{"time":"2021-01-03","value":5}]}
    {"data":[{"time":"2021-01-01","value":10},{"time":"2021-01-02","value":100},{"time":"2021-01-03","value":50}]}
    

    【讨论】:

    • 您曾两次致电jq。可以通过一个电话完成吗?
    • @Philippe 是的,您可以将-c[] 添加到第一个jq 调用中。不过,我并不总是喜欢最紧凑的解决方案。我通常更喜欢清晰地分离关注点。这就是管道的伟大之处。在这种情况下,我认为向 OP 展示每个步骤的作用更为重要。
    • 很清楚解释bash循环,谢谢
    猜你喜欢
    • 1970-01-01
    • 2014-02-17
    • 2017-12-02
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多