😽
jq commandの select でハマった話
結論
配列のjsonに対してselectする際には、配列を一度オブジェクトの抽出をしないと複製されてしまう。
なので、以下ではなく
jq -r 'select(.[].A | contains("特定文字列")) | .[].B' test.json
こうしないといけない
jq -r '.[] | select(.A | contains("特定文字列")) | .B' test.json
環境
$ jq --version
jq-1.6
詰まった内容
以下のjson(test.json)があったときに
test.json
[
{
"hoge": "aba",
"fuga": "bbb"
},
{
"hoge": "ccc",
"fuga": "ddd"
},
{
"hoge": "aab",
"fuga": "ccc"
}
]
hogeのvalueで ab
が入っているfugaの値を抜き出したいとします。以下の形を想定しています。
bbb
ccc
この際に以下のような書き方をすると
jq -r 'select(.[].hoge | contains("ab")) | .[].fuga' test.json
結果は以下のようになります。
aba
ccc
aab
aba
ccc
aab
検証
試しに、以下のようにやってみるとリストが3つ作成されています。
jq -r 'select(.[].hoge)' test.json
結果
[
{
"hoge": "aba",
"fuga": "bbb"
},
{
"hoge": "ccc",
"fuga": "ddd"
},
{
"hoge": "aab",
"fuga": "ccc"
}
]
[
{
"hoge": "aba",
"fuga": "bbb"
},
{
"hoge": "ccc",
"fuga": "ddd"
},
{
"hoge": "aab",
"fuga": "ccc"
}
]
[
{
"hoge": "aba",
"fuga": "bbb"
},
{
"hoge": "ccc",
"fuga": "ddd"
},
{
"hoge": "aab",
"fuga": "ccc"
}
]
で以下のように | contains("ab")
をつけると2つになっています
jq -r 'select(.[].hoge | contains("ab"))' test.json
結果
[
{
"hoge": "aba",
"fuga": "bbb"
},
{
"hoge": "ccc",
"fuga": "ddd"
},
{
"hoge": "aab",
"fuga": "ccc"
}
]
[
{
"hoge": "aba",
"fuga": "bbb"
},
{
"hoge": "ccc",
"fuga": "ddd"
},
{
"hoge": "aab",
"fuga": "ccc"
}
]
つまり、先程の場合、「リスト一つを一つのオブジェクトとして認識しつつ、かつ、その中の .hoge
の値を検証するため、各リストの中の .hoge
の分だけオブジェクト(リスト)が作られ、それぞれを検証する」という感じのようです。
なので、今回の要件に合わせるには、一度リストからオブジェクトを取得してから実施する .[]
を最初にやる必要があるということですね。
jq -r '.[] | select(.hoge | contains("ab"))' test.json
結果
{
"hoge": "aba",
"fuga": "bbb"
}
{
"hoge": "aab",
"fuga": "ccc"
}
だとしても、増えるのは。。。良くないよなぁ、と勝手に思っていた土曜日の夜。
Discussion