jq의 출력 깊이를 제한합니다.

jq의 출력 깊이를 제한합니다.

를 사용하여 임의의 문서를 탐색하고 싶습니다 jq. 이를 위해 jq문서의 깊이를 제한하고 첫 번째 n(가령 3) 수준 만 표시하고 싶습니다 .

다음 JSON 문서가 있다고 가정해 보겠습니다.

{
    "a": {
        "b": {
            "c": {
                "d": {
                    "e": "foo"
                }
            }
        }
    },
    "f": {
        "g": {
            "h": {
                "i": {
                    "j": "bar"
                }
            }
        }
    },
    "k": {
        "l": {
            "m": {
                "n": {
                    "o": "baz"
                }
            }
        }
    }
}

나는 결과를 기대한다

{
    "a": {
        "b": {
            "c": {}
        }
    },
    "f": {
        "g": {
            "h": {}
        }
    },
    "k": {
        "l": {
            "m": {}
        }
    }
}

문서의 구조를 미리 알고 있다면 상당히 간단한 작업이지만 그렇지 않은 경우가 많습니다. 이것이 jq바로 문서 구조의 처음 n개 수준만 표시 할 수 있기를 원하는 이유입니다 . 이는 사전과 배열이 임의로 중첩될 수 있습니다.

더 복잡한 예는 다음과 같습니다.

[
    { "a": { "b": { "c": { "d": { "e": "foo"}}}}},
    { "f": [ { "g": "foo"}]},
    [ "h", "i", "j" ]
]

내가 결과를 기대하는 곳

[
    { "a": { "b": {}},
    { "f": [{}]},
    [ "h", "i", "j" ]
]

내가 jq이걸 할 수 있을까?

답변1

del함수를 배열/객체 값 반복자와 결합하여 .[]?네 번째 중첩 수준에서 키/값을 제거하면 원하는 결과를 얻을 수 있는 것 같습니다.

$ jq 'del(.[]?[]?[]?[]?)' <<'EOT'
[
    { "a": { "b": { "c": { "d": { "e": "foo"}}}}},
    { "f": [ { "g": "foo"}]},
    [ "h", "i", "j" ]
]
EOT
[
  {
    "a": {
      "b": {}
    }
  },
  {
    "f": [
      {}
    ]
  },
  [
    "h",
    "i",
    "j"
  ]
]

.[]?배열이나 객체가 아닌 항목을 반복하려고 할 때 불만을 방지하려면 반복기 필터 버전이 필요합니다 ..[]jq

솔직히 말해서 .[][]문서 어디에서도 위에 표시된 형식(기본적으로: )의 배열/객체 반복자 필터에 대한 직접적인 언급을 찾을 수 없습니다. 덜 간결하지만 명확하게 문서화된 버전은 다음과 같습니다.

$ jq 'del(.[]? | .[]? | .[]? | .[]?)' ...

답변2

를 사용하면 path(..)특정 문서에 대해 가능한 모든 경로 표현식을 생성할 수 있습니다. 그런 다음 select(length > 3)예를 들어 너무 긴 것을 선택할 수 있습니다 . 로 삭제할 수 있습니다 delpaths().

jq이는 단일 정수( with 로 전달할 수 있음 --argjson) 로 쉽게 매개변수화할 수 있지만 path(..)동시에 불필요하게 "무거운"(결과를 산출하는) 간결해 보이는 표현식을 작성할 수 있다는 장점이 있습니다.모든문서의 경로).

$ jq 'delpaths([path(..) | select(length > 3)])' file
{
  "a": {
    "b": {
      "c": {}
    }
  },
  "f": {
    "g": {
      "h": {}
    }
  },
  "k": {
    "l": {
      "m": {}
    }
  }
}

질문 끝에 있는 예제 문서를 사용하여 테스트하세요.

$ jq . file
[
  {
    "a": {
      "b": {
        "c": {
          "d": {
            "e": "foo"
          }
        }
      }
    }
  },
  {
    "f": [
      {
        "g": "foo"
      }
    ]
  },
  [
    "h",
    "i",
    "j"
  ]
]
$ jq --argjson d 1 'delpaths([path(..) | select(length > $d)])' file
[
  {},
  {},
  []
]
$ jq --argjson d 2 'delpaths([path(..) | select(length > $d)])' file
[
  {
    "a": {}
  },
  {
    "f": []
  },
  [
    "h",
    "i",
    "j"
  ]
]
$ jq --argjson d 3 'delpaths([path(..) | select(length > $d)])' file
[
  {
    "a": {
      "b": {}
    }
  },
  {
    "f": [
      {}
    ]
  },
  [
    "h",
    "i",
    "j"
  ]
]

답변3

이 방법은 jq 버전마다 변경될 수 있는 공백에 의존하기 때문에 이상적이지 않을 수 있지만, 다른 도구를 사용하여 유사한 상황에 적용할 수 있다는 점에서는 강력한 방법입니다.

jq는 예쁜 인쇄를 완료한 후 json 트리 아래 요소 앞에 공백을 추가합니다. 따라서 특정 개수의 선행 공백이 있는 줄에서 역방향 grep을 수행하면 특정 깊이를 넘어서는 모든 요소를 ​​제거할 수 있습니다. 아래 예에서는 귀하의 예와 유사하게 깊이가 4 이상인 요소를 제거했습니다.

grifball@grifball-Computer:~$ cat limit-output.json
{"a":{"b":{"c":{"d":{"e":"foo"}}}},"f":{"g":{"h":{"i":{"j":"bar"}}}},"k":{"l":{"m":{"n":{"o":"baz"}}}}}
grifball@grifball-Computer:~$ cat limit-output.json | jq
{
  "a": {
    "b": {
      "c": {
        "d": {
          "e": "foo"
        }
      }
    }
  },
  "f": {
    "g": {
      "h": {
        "i": {
          "j": "bar"
        }
      }
    }
  },
  "k": {
    "l": {
      "m": {
        "n": {
          "o": "baz"
        }
      }
    }
  }
}
grifball@grifball-Computer:~$ cat limit-output.json | jq | grep -v '^\s\{8\}'
{
  "a": {
    "b": {
      "c": {
      }
    }
  },
  "f": {
    "g": {
      "h": {
      }
    }
  },
  "k": {
    "l": {
      "m": {
      }
    }
  }
}

관련 정보