Quantcast
Channel: Bashタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 2861

jq + bash (zsh) でリストっぽいデータを処理する

$
0
0

配列っぽいデータが含まれるJSONデータをjqコマンドとシェルを組み合わせて処理する方法.

こういう感じのJSONデータ (states.json) があるとして.

{"states":[{"name":"北海道","name_ac":"ほっかいどう"},{"name":"青森","name_ac":"あおもり"},{"name":"岩手","name_ac":"いわて"},{"name":"宮城","name_ac":"みやぎ"},{"name":"秋田","name_ac":"あきた"},{"name":"山形","name_ac":"やまがた"},{"name":"福島","name_ac":"ふくしま"}]}

こんな感じで出力させるものとする.

北海道 ほっかいどう
青森 あおもり
岩手 いわて
宮城 みやぎ
秋田 あきた
山形 やまがた
福島 ふくしま

整形して出力

単にJSONを見やすく整形出力したいなら, これだけ.

jq '.'< states.json

JSONのなかの特定のプロパティにアクセスする

プロパティ名を指定すればよい.

jq '.states'< states.json

次の結果が得られる.

[
  {
    "name": "北海道",
    "name_ac": "ほっかいどう"
  },
  {
    "name": "青森",
    "name_ac": "あおもり"
  },
  {
    "name": "岩手",
    "name_ac": "いわて"
  },
  {
    "name": "宮城",
    "name_ac": "みやぎ"
  },
  {
    "name": "秋田",
    "name_ac": "あきた"
  },
  {
    "name": "山形",
    "name_ac": "やまがた"
  },
  {
    "name": "福島",
    "name_ac": "ふくしま"
  }
]

シーケンシャルに処理できるようにする

配列などのデータを扱うなら, for/while で処理できたほうがいい.
jqの機能 length と seqコマンドを組み合わせる例を見かけることがあるけど, 個人的にはwhileを好む.

jq -c'.states[]'< states.json

-cオプションで, 出力されるJSONを1行にできる.
フィルタ (ここまであげた例でいうシングルクォートでくくってる箇所) で指定してるプロパティに []をつけると,
1アイテムを1行ずつ出力してくれる.

{"name":"北海道","name_ac":"ほっかいどう"}
{"name":"青森","name_ac":"あおもり"}
{"name":"岩手","name_ac":"いわて"}
{"name":"宮城","name_ac":"みやぎ"}
{"name":"秋田","name_ac":"あきた"}
{"name":"山形","name_ac":"やまがた"}
{"name":"福島","name_ac":"ふくしま"}

whileループで処理する

ここまでできると, パイプと while readとさらにjqコマンドを組み合わせることで,
各アイテムごとのプロパティにアクセスできるようになる.

jq -c'.states[]'< states.json | \while read state;do
        jq -r'[.name, .name_ac] | @tsv'<<<$state | (read name name_ac
            echo$name$name_ac)done

-rオプションでダブルクォートでくくるのをなしにしている.
フィルタでは [.name, .name_ac]でリストっぽい出力にし, jqの組み込み機能でtsv (タブ区切りのシーケンス) に変換し, readコマンドで変数へセットしてる.

readで各アイテムを読みだした後, 変数へセットするところは, 素直に次のように書いてもいいと思う.
(jqコマンドの呼び出しは少なくできるけど, 値にスペースが含まれてることを考えると, このほうが使いやすいかも)

jq -c'.states[]'< states.json | \while read state;do
        name=$(jq -r'.name'<<<$state)name_ac=$(jq -r'.name_ac'<<<$state)echo$name$name_acdone

Viewing all articles
Browse latest Browse all 2861

Trending Articles