Rubyでいうinclude?
的なことをやりたかったがさっとできなかったのでメモを残す
サンプルはこんな感じ
$ cat sample.json [ { "user": "hoge", "team": "" }, { "user": "fuga", "team": "" }, { "user": "piyo", "team": "" }, { "user": "foo", "team": "" }, { "user": "bar", "team": "" } ]
hoge,fugaはteam: Aで、foo,barはteam: Bでという感じで値を入れていく場合
ぱっとマニュアル見た感じはinside
やcontains
かなと思ったので色々試してみたもののうまく行かず
いったんおさらい
contains
条件が完全に含まれる場合はtrueを返す
例を見ると単純な文字列比較のときはわかりやすいが配列やハッシュが含まれると理解が追いつかなくなる…
条件で指定する文字列が入力に含まれてますか?ということらしい
文字列比較の場合は部分一致、配列やハッシュの場合はその構造が包含されるか
$ echo '"foobar"' | jq 'contains("bar")' true
入力foobar
にbar
という文字列が含まれていますか?という感じ
inside
containsの逆、これは入力と条件が逆という意味合いっぽい
文面読んでサンプル見ただけだと「分かりづらい…」と感じたけど実際に試してみると理解しやすかった
$ echo '"bar"' | jq 'inside("foobar")' true
こういうことか!という感じ
containsも同様だが、入力と同じ型でないと比較ができないよう
$ echo '"fuga"' | jq 'inside(["fuga"])' jq: error (at <stdin>:1): array (["fuga"]) and string ("fuga") cannot have their containment checked
型をそろえてあげればOK
$ echo '["fuga"]' | jq 'inside(["hoge","fuga"])' true
ということで冒頭の例を実現できるように書くと次のようになる
cat sample.json| jq '.[]|if([.user]|inside(["hoge","fuga"])) then .team="A" elif([.user]|inside(["foo","bar"])) then .team="B" else . end' { "user": "hoge", "team": "A" } { "user": "fuga", "team": "A" } { "user": "piyo", "team": "" } { "user": "foo", "team": "B" } { "user": "bar", "team": "B" }
他の解決パターン
最初こっちのパターンで処理していた
test
を使って行うことも可能
cat sample.json | jq '.[]|if(.user|test("(hoge|fuga)")) then .team="A" elif(.user|test("(foo|bar)")) then .team="B" else . end' { "user": "hoge", "team": "A" } { "user": "fuga", "team": "A" } { "user": "piyo", "team": "" } { "user": "foo", "team": "B" } { "user": "bar", "team": "B" }
まとめ
右往左往したけど正規表現で色々やる必要がなければinside
のほうが良さそうに感じた
また1つjqレベルが上がりました