CUBE SUGAR STORAGE

技術系のことかきます。
Recent Tweets @

JSON の内容を sed や awk のようにフィルタ・加工するためのプログラムに jq がある。 JSON 形式で提供されている WebAPI の出力や、ログの内容を扱うのにとても便利。 その強力さの一端を紹介したい。

インストールは Mac OS X であれば Homebrew から。公式サイトからバイナリをダウンロードすることもできる。

$ brew install jq

サンプル用の JSON を用意しておく。
$ cat << EOS > jsonfile
{"name": "Foo", "sex": "Male", "age": 15, "emails": []}
{"name": "Bar", "sex": "Male", "age": 20, "emails": ["hoge@example.jp"]}
{"name": "Baz", "sex": "Female", "emails": ["fuga@example.net", "piyo@example.org"]}
EOS
$ cat jsonfile
{"name": "Foo", "sex": "Male", "age": 15, "emails": []}
{"name": "Bar", "sex": "Male", "age": 20, "emails": ["hoge@example.jp"]}
{"name": "Baz", "sex": "Female", "emails": ["fuga@example.net", "piyo@example.org"]}

まずは最も単純な使い方。 jq は標準入力の内容を JSON として解釈する。 ルート要素 (.) を指定して実行するだけで、JSON が整形されて出力される。
$ cat jsonfile | jq '.'
{
  "emails": [],
  "age": 15,
  "sex": "Male",
  "name": "Foo"
}
{
  "emails": [
    "hoge@example.jp"
  ],
  "age": 20,
  "sex": "Male",
  "name": "Bar"
}
{
  "emails": [
    "fuga@example.net",
    "piyo@example.org"
  ],
  "sex": "Female",
  "name": "Baz"
}

特定の要素 (name) の値だけを取り出してみる。 配列の要素として指定しても良さげ。
$ cat jsonfile | jq '.name'
"Foo"
"Bar"
"Baz"
$ cat jsonfile | jq '.["name"]'
"Foo"
"Bar"
"Baz"

配列なども同様に取り出せる。 [] を指定すると配列の要素を展開できる。
$ cat jsonfile | jq '.emails'
[]
[
  "hoge@example.jp"
]
[
  "fuga@example.net",
  "piyo@example.org"
]
$ cat jsonfile | jq '.emails[]'
"hoge@example.jp"
"fuga@example.net"
"piyo@example.org"

JSON の内容を組み替え直すこともできる。 例えば、name, age だけ取り出した JSON (辞書, 配列) に直す。
$ cat jsonfile | jq '.name, .age'
"Foo"
15
"Bar"
20
"Baz"
null
$ cat jsonfile | jq '{name, age}'
{
  "age": 15,
  "name": "Foo"
}
{
  "age": 20,
  "name": "Bar"
}
{
  "age": null,
  "name": "Baz"
}
$ cat jsonfile | jq '[.name, .age]'
[
  "Foo",
  15
]
[
  "Bar",
  20
]
[
  "Baz",
  null
]

キーの名前を変更したり、特定の値と値 (以下は “name” と “emails” の対応付け) を紐付けた形に直すこともできる。
$ cat jsonfile | jq '{"namae": .name}'
{
  "namae": "Foo"
}
{
  "namae": "Bar"
}
{
  "namae": "Baz"
}
$ cat jsonfile | jq '{(.name): .emails}'
{
  "Foo": []
}
{
  "Bar": [
    "hoge@example.jp"
  ]
}
{
  "Baz": [
    "fuga@example.net",
    "piyo@example.org"
  ]
}

値の内容をそのまま使うだけでなく、変更もできる。 年齢を 5 歳サバを読ませてみよう。null + 5 は 5 になるので、null は 0 として扱われているようだ。
$ cat jsonfile | jq '{name, "age": (.age + 5)}'
{
  "age": 20,
  "name": "Foo"
}
{
  "age": 25,
  "name": "Bar"
}
{
  "age": 5,
  "name": "Baz"
}

更に、加工するのに便利な組み込み関数が色々と用意されている。 メールアドレスの長さを取り出すのに length 関数を使ってみる。
$ cat jsonfile | jq '.emails[]'
"hoge@example.jp"
"fuga@example.net"
"piyo@example.org"
$ cat jsonfile | jq '.emails[] | length'
15
16
16

キーだけを取り出すなら keys 関数を使う。
$ cat jsonfile | jq 'keys'
[
  "age",
  "emails",
  "name",
  "sex"
]
[
  "age",
  "emails",
  "name",
  "sex"
]
[
  "emails",
  "name",
  "sex"
]

特定の条件が真になる要素を取り出すには select を使うと良い。 以下では性別や年齢を条件にして要素をフィルタしている。
$ cat jsonfile | jq 'select(.sex == "Male")'
{
  "emails": [],
  "age": 15,
  "sex": "Male",
  "name": "Foo"
}
{
  "emails": [
    "hoge@example.jp"
  ],
  "age": 20,
  "sex": "Male",
  "name": "Bar"
}
$  cat jsonfile | jq 'select(.age > 15)'
{
  "emails": [
    "hoge@example.jp"
  ],
  "age": 20,
  "sex": "Male",
  "name": "Bar"
}
$ cat jsonfile | jq 'select(.age < 20 and .age > 10)'
{
  "emails": [],
  "age": 15,
  "sex": "Male",
  "name": "Foo"
}

特定の要素が存在するか検査するには has 関数が使える。
$ cat jsonfile | jq 'has("age")'
true
true
false
$ cat jsonfile | jq 'select(has("age"))'
{
  "emails": [],
  "age": 15,
  "sex": "Male",
  "name": "Foo"
}
{
  "emails": [
    "hoge@example.jp"
  ],
  "age": 20,
  "sex": "Male",
  "name": "Bar"
}

より大きく、特定の要素を含むことを表すには contains 関数が使える。
$  cat jsonfile | jq 'select(contains({age:20}))'
{
  "emails": [
    "hoge@example.jp"
  ],
  "age": 20,
  "sex": "Male",
  "name": "Bar"
}

if 文が使えたりもする。
$  cat jsonfile | jq 'if .age >= 20 then "adult" else "minor" end'
"minor"
"adult"
"minor"

これまで JSON の内容の整形や加工はスクリプトでも書いてやってたけど、多くの場合はこれで事足りてしまいそうなほど jq は強力。 jq で加工した内容を更にパイプで別のコマンドに繋いでいく、っていう使い方もできるし。 尚、公式のマニュアルを見ると上記以外の組み込み関数やテクニックもたくさん紹介されている。
  1. emisuky reblogged this from momijiame
  2. orekane reblogged this from momijiame
  3. hakuro reblogged this from momijiame
  4. uokada reblogged this from momijiame
  5. susatadahiro reblogged this from momijiame
  6. namidame reblogged this from momijiame
  7. makowis reblogged this from momijiame
  8. beinteractive reblogged this from momijiame
  9. brettspieler reblogged this from atm09td
  10. atm09td reblogged this from act2012bl
  11. act2012bl reblogged this from hookturn
  12. hookturn reblogged this from momijiame
  13. haru012 reblogged this from momijiame
  14. hlwtknng reblogged this from pioc-blog
  15. pioc-blog reblogged this from momijiame
  16. konekozanmai reblogged this from momijiame
  17. chizuna reblogged this from bgnori-technology
  18. bgnori-technology reblogged this from momijiame
  19. farvel reblogged this from momijiame
  20. moriwaka reblogged this from momijiame
  21. momijiame posted this