在 shell 脚本中循环遍历 JSON 数组

Sug*_*S N 14 shell scripting json jq

下面是 curl 命令输出(关于分支的文件信息),需要脚本或命令来打印文件名、文件类型和大小。

我尝试过jq但能够获取单个值 ( jq '.values[].size')

{
  "path": {
    "components": [],
    "name": "",
    "toString": ""
  },
  "revision": "master",
  "children": {
    "size": 5,
    "limit": 500,
    "isLastPage": true,
    "values": [
      {
        "path": {
          "components": [
            ".gitignore"
          ],
          "parent": "",
          "name": ".gitignore",
          "extension": "gitignore",
          "toString": ".gitignore"
        },
        "contentId": "c9e472ef4e603480cdd85012b01bd5f4eddc86c6",
        "type": "FILE",
        "size": 224
      },
      {
        "path": {
          "components": [
            "Jenkinsfile"
          ],
          "parent": "",
          "name": "Jenkinsfile",
          "toString": "Jenkinsfile"
        },
        "contentId": "e878a88eed6b19b2eb0852c39bfd290151b865a4",
        "type": "FILE",
        "size": 1396
      },
      {
        "path": {
          "components": [
            "README.md"
          ],
          "parent": "",
          "name": "README.md",
          "extension": "md",
          "toString": "README.md"
        },
        "contentId": "05782ad495bfe11e00a77c30ea3ce17c7fa39606",
        "type": "FILE",
        "size": 237
      },
      {
        "path": {
          "components": [
            "pom.xml"
          ],
          "parent": "",
          "name": "pom.xml",
          "extension": "xml",
          "toString": "pom.xml"
        },
        "contentId": "9cd4887f8fc8c2ecc69ca08508b0f5d7b019dafd",
        "type": "FILE",
        "size": 2548
      },
      {
        "path": {
          "components": [
            "src"
          ],
          "parent": "",
          "name": "src",
          "toString": "src"
        },
        "node": "395c71003030308d1e4148b7786e9f331c269bdf",
        "type": "DIRECTORY"
      }
    ],
    "start": 0
  }
}
Run Code Online (Sandbox Code Playgroud)

预期输出应如下所示

.gitignore    FILE     224

Jenkinsfile   FILE     1396
Run Code Online (Sandbox Code Playgroud)

Jig*_*aga 21

提取成员

jq -c '.children.values[]|[.path.components[0],.type,.size]'
Run Code Online (Sandbox Code Playgroud)
  • .children.values[]输出数组的每个成员.values
  • | 将前一个结果通过下一个过滤器进行管道传输,就像一个壳管
  • [... ,... ,...]使里面的所有项都出现在一个数组中
  • -c选项产生“紧凑”格式,即。每行一个对象

结果:

[".gitignore","FILE",224]
["Jenkinsfile","FILE",1396]
["README.md","FILE",237]
...
Run Code Online (Sandbox Code Playgroud)

格式化结果

如果你想输出一个整齐对齐的表格,这是一项由其他工具更好地处理的任务,例如columnpaste

jq -c '.children.values[]|[.path.components[0],.type,.size]' | column -t -s'[],"'
Run Code Online (Sandbox Code Playgroud)
  • -t告诉column根据输入猜测列数
  • -s... 指定分隔符

结果:

.gitignore   FILE       224
Jenkinsfile  FILE       1396
README.md    FILE       237
Run Code Online (Sandbox Code Playgroud)

这依赖于字符[, ],,并且"没有出现在您的文件名中,这不是一个安全的假设。

paste还可以并排排列多个输入。为此,我们可以完全删除 JSON 结构,并输出原始行(给@muru 的帽子提示):

jq -r '.children.values[]|.path.components[0],.type,.size' | paste - - -
Run Code Online (Sandbox Code Playgroud)

paste - - -表示 3 列,均从同一来源读取。这一次,唯一的假设是文件名不包含换行符。


pLu*_*umo 20

对于问题中提供的用例,@JigglyNaga 的答案可能比这更好,但对于一些更复杂的任务,您还可以使用keys以下方法遍历列表项:

来自file

for k in $(jq '.children.values | keys | .[]' file); do
    ...
done
Run Code Online (Sandbox Code Playgroud)

或从字符串:

for k in $(jq '.children.values | keys | .[]' <<< "$MYJSONSTRING"); do
    ...
done
Run Code Online (Sandbox Code Playgroud)

所以例如你可能会使用:

for k in $(jq '.children.values | keys | .[]' file); do
    value=$(jq -r ".children.values[$k]" file);
    name=$(jq -r '.path.name' <<< "$value");
    type=$(jq -r '.type' <<< "$value");
    size=$(jq -r '.size' <<< "$value");
    printf '%s\t%s\t%s\n' "$name" "$type" "$size";
done | column -t -s$'\t'
Run Code Online (Sandbox Code Playgroud)

如果您没有值的换行符,您可以通过jq在循环内进行一次调用来使其更快:

for k in $(jq '.children.values | keys | .[]' file); do
    IFS=$'\n' read -r -d '' name type size \
        <<< "$(jq -r ".children.values[$k] | .path.name,.type,.size" file)"
    printf '%s\t%s\t%s\n' "$name" "$type" "$size";
done | column -t -s$'\t'
Run Code Online (Sandbox Code Playgroud)


gle*_*man 5

jq可以将其输出呈现为多种格式:参见https://stedolan.github.io/jq/manual/#Formatstringsandescaping

对于制表符分隔的输出:

$ jq -r '.children.values[] | [.path.name, .type, .size] | @tsv' file.json
.gitignore  FILE    224
Jenkinsfile FILE    1396
README.md   FILE    237
pom.xml FILE    2548
src DIRECTORY   
Run Code Online (Sandbox Code Playgroud)