从嵌套在巨大深度JSON文件中不同深度的对象中提取数据

时间:2019-01-23 14:20:48

标签: json bash shell loops

我使用以下代码从巨大的json格式文件中获取数据。

_ITEM_L1=`cat json.list | jq .item[].length | wc -l`
for (( i=0;i<$_ITEM_L1;i++ ));
do
    _ITEM_L2=`cat json.list | jq .item[$i].item[].length | wc -l`
    for (( j=0;j<$_ITEM_L2;j++ ));
    do
        _API_NAME=`cat json.list | jq .item[$i].item[$j].name`
        _API_URL=`cat json.list | jq .item[$i].item[$j].request.url.raw`
        echo $_API_NAME
        echo $_API_URL;
    done;
done

起初,我认为它只有2个级别,但是运行脚本时发现它超过2个级别,可能是3或4甚至5或更多。 所以我的问题是在开始迭代之前如何知道json文件中有多少级?

item0
    |
    item0
         |
         item0
              name:
              url:
         item1
              name:
              url:
         item2
              name:
              url:
    item1
         |
         item0
              |
              item0
                   name:
                   url:
              item1
                   name:
                   url:
         item1
              |
              item0
                   name:
                   url:
              item1
                   name:
                   url:
              item2
                   name:
                   url:
item1
     |
     item0
          name:
          url:
     item1
          name:
          url:
     item2
          name:
          url:
.
.
.
.
.
.

1 个答案:

答案 0 :(得分:0)

更好的设计不会要求,您不必知道文件中有多少层嵌套深度,并且绝对不会调用{{1} }一遍又一遍! ({jq是一种完善的编程语言-它可以自行循环,并且仅通过一次jq调用处理整个文件,而不是使用不同的过滤器一遍又一遍地处理,效率要高得多)。


让我们从一个具体的示例输入开始:

jq

要将其转换为扁平的名称/ URL对对,可以使用:

{
  "item0": {
    "item0a": {
      "item0aA": {
        "name": "foo",
        "url": "bar"
      },
      "item0aB": {
        "name": "baz",
        "url": "qux"
      }
    }
  },
  "item1": {
    "name": "qux",
    "url": "quux"
  }
}

将作为输出发出:

jq -r '.. | objects | select(.name? != null) | [ .name, .url ] | @tsv'

...您可以在bash中轻松对其进行迭代:

foo bar
baz qux
qux quux

了解其工作原理:

  • while IFS=$'\t' read -r name url; do echo "Read name $name and url $url" done < <(jq -r '.. | objects | select(.name? != null) | [ .name, .url ] | @tsv' <json.list) 是jq的递归下降算子。
  • ..忽略不是对象的东西。
  • objects仅过滤具有名称的对象。 (可以类似地只过滤具有相同网址的对象)。
  • .name? != null将输出以制表符分隔的值形式。
  • @tsv将输入行读入变量IFS=$'\t' read -r name urlname,并用制表符将它们分开。