jqで相対パスを指定してJSONの要素を取得したい。

以下のようなJSONから"aaaa"だけ抜き出したい場合を考える。

$ cat sample.json | jq .
{
  "a": {
    "aa": {
      "aaa": {
        "aaaa": "a4"
      }
    }
  }
}

通常であれば絶対パスを指定する。

$ cat sample.json | jq -r .a.aa.aaa.aaaa
a4

これを相対パスで"aaaa"だけを指定して取得したい。

$ cat sample.json | jq -r '..|select(.aaaa)?'
{
  "aaaa": "a4"
}

相対パスは..で始める。XMLでいうところの//と同じだが、..の直後は必ずパイプ|を繋げなければならない。selectでKeyが"aaaa"のものを抜き出している。

この結果にさらにパイプでKeyを指定すれば値だけがとれる。

$ cat sample.json | jq -r '..|select(.aaaa)?|.aaaa'
a4

"aaaa"の値が"a4"でなければならないといった条件があれば、その条件もselectに書ける。

$ cat sample.json | jq -r '..|select(.aaaa=="a4")?'
{
  "aaaa": "a4"
}