jqコマンド練習

jqコマンドは圧縮されたjsonを整形してくれる便利なツールです。
もちろん必要なところだけを抽出したりなどもできます。
いつもはjsonの整形くらいにしか使ってなかったのだけれど、いろいろ使えそうだったので遊んでみます。

チュートリアルはjqの公式にあるのでまずはそこから。

Tutorial

公式だとcurlで都度responseを返してますが、
レスポンスを待つのが面倒なので一旦ファイルに書き出してそこを読むようにします。
curlで取得してるのは、githubの最新5件のcommit logです。

$ curl 'https://api.github.com/repos/stedolan/jq/commits?per_page=5' > json_response

下記のように使います。(行数多いので割愛)

$ cat json_response | jq

最新のコミット分だけ取得する。
鉤括弧中の数字をインクリメントすれば2件目や3件目を取得できる。

$ cat json_response | jq .[0]
{
  "sha": "0b8218515eabf1a967eba0dbcc7a0e5ae031a509",
  "commit": {
    "author": {
      "name": "Nicolas Williams",
      "email": "nico@cryptonector.com",
      "date": "2016-03-21T22:43:01Z"
    },
    "committer": {
      "name": "Nicolas Williams",
      "email": "nico@cryptonector.com",
      "date": "2016-03-21T23:59:52Z"
    },
    "message": "Disable appveyor build for now",
    "tree": {
      "sha": "4920056437c4f768f24b2771309eddac55f55645",
      "url": "https://api.github.com/repos/stedolan/jq/git/trees/4920056437c4f768f24b2771309eddac55f55645"
    },
    "url": "https://api.github.com/repos/stedolan/jq/git/commits/0b8218515eabf1a967eba0dbcc7a0e5ae031a509",
    "comment_count": 3
  },
  "url": "https://api.github.com/repos/stedolan/jq/commits/0b8218515eabf1a967eba0dbcc7a0e5ae031a509",
  "html_url": "https://github.com/stedolan/jq/commit/0b8218515eabf1a967eba0dbcc7a0e5ae031a509",
  "comments_url": "https://api.github.com/repos/stedolan/jq/commits/0b8218515eabf1a967eba0dbcc7a0e5ae031a509/comments",
  "author": {
    "login": "nicowilliams",
    "id": 604851,
    "avatar_url": "https://avatars.githubusercontent.com/u/604851?v=3",
    "gravatar_id": "",
    "url": "https://api.github.com/users/nicowilliams",
    "html_url": "https://github.com/nicowilliams",
    "followers_url": "https://api.github.com/users/nicowilliams/followers",
    "following_url": "https://api.github.com/users/nicowilliams/following{/other_user}",
    "gists_url": "https://api.github.com/users/nicowilliams/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/nicowilliams/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/nicowilliams/subscriptions",
    "organizations_url": "https://api.github.com/users/nicowilliams/orgs",
    "repos_url": "https://api.github.com/users/nicowilliams/repos",
    "events_url": "https://api.github.com/users/nicowilliams/events{/privacy}",
    "received_events_url": "https://api.github.com/users/nicowilliams/received_events",
    "type": "User",
    "site_admin": false
  },
  "committer": {
    "login": "nicowilliams",
    "id": 604851,
    "avatar_url": "https://avatars.githubusercontent.com/u/604851?v=3",
    "gravatar_id": "",
    "url": "https://api.github.com/users/nicowilliams",
    "html_url": "https://github.com/nicowilliams",
    "followers_url": "https://api.github.com/users/nicowilliams/followers",
    "following_url": "https://api.github.com/users/nicowilliams/following{/other_user}",
    "gists_url": "https://api.github.com/users/nicowilliams/gists{/gist_id}",
    "starred_url": "https://api.github.com/users/nicowilliams/starred{/owner}{/repo}",
    "subscriptions_url": "https://api.github.com/users/nicowilliams/subscriptions",
    "organizations_url": "https://api.github.com/users/nicowilliams/orgs",
    "repos_url": "https://api.github.com/users/nicowilliams/repos",
    "events_url": "https://api.github.com/users/nicowilliams/events{/privacy}",
    "received_events_url": "https://api.github.com/users/nicowilliams/received_events",
    "type": "User",
    "site_admin": false
  },
  "parents": [
    {
      "sha": "1a8a5ee00078aa5bd977f575e3e5ecad4e467487",
      "url": "https://api.github.com/repos/stedolan/jq/commits/1a8a5ee00078aa5bd977f575e3e5ecad4e467487",
      "html_url": "https://github.com/stedolan/jq/commit/1a8a5ee00078aa5bd977f575e3e5ecad4e467487"
    }
  ]
}

もちろん5件しかないので、数字を5にするとnullが返ってくる

$ cat json_response | jq '.[5]'
null

一番新しいコミットからユーザとコミットメッセージだけを取得する。
パイプでつなげてメッセージを整形することもできます。

$ cat json_response | jq '.[0] | {message: .commit.message, name: .commit.committer.name}'
{
  "message": "Disable appveyor build for now",
  "name": "Nicolas Williams"
}

鉤括弧中の数字を消しておけば、5件分取得できる

$ cat json_response | jq '.[] | {message: .commit.message, name: .commit.committer.name}'
{
  "message": "Disable appveyor build for now",
  "name": "Nicolas Williams"
}
{
  "message": "Remove David from maintainers",
  "name": "David Tolnay"
}
{
  "message": "Travis-CI build for OSX (fix #1083)",
  "name": "Nicolas Williams"
}
{
  "message": "Always test sort_by/group_by post-#1082",
  "name": "Nicolas Williams"
}
{
  "message": "Make jv_sort stable regardless of qsort details.",
  "name": "Nicolas Williams"
}

jqコマンドでいろいろ遊んでます。
今回実験で使うjsonは下記です。
jsonというファイル名で保存してます。

{"StartingInstances":[{"InstanceId":"i-ee880f4b","CurrentState":{"Code":0,"Name":"pending"},"PreviousState":{"Code":80,"Name":"stopped"}},{"InstanceId":"i-275d1ed5","CurrentState":{"Code":0,"Name":"pending"},"PreviousState":{"Code":80,"Name":"stopped"}},{"InstanceId":"i-83dc2667","CurrentState":{"Code":0,"Name":"pending"},"PreviousState":{"Code":80,"Name":"stopped"}},{"InstanceId":"i-0f41842b","CurrentState":{"Code":16,"Name":"running"},"PreviousState":{"Code":16,"Name":"running"}},{"InstanceId":"i-002dc13f","CurrentState":{"Code":16,"Name":"running"},"PreviousState":{"Code":16,"Name":"running"}}]}

オブジェクトの数を取得

$ cat json | jq '.[] | length'
5

InstanceIdだけを取得してみる

$ cat json | jq '.[]  | .[].InstanceId'
"i-ee880f4b"
"i-275d1ed5"
"i-83dc2667"
"i-0f41842b"
"i-002dc13f"

CurrentStateのステータスコードが16(runnning)のものだけを取得

$ cat json | jq '.[] | .[].CurrentState | select(.Code == 16)'
{
  "Code": 16,
  "Name": "running"
}
{
  "Code": 16,
  "Name": "running"
}

CurrentStateのステータスrunningのものだけを取得

$ cat json | jq '.[] | .[].CurrentState | select(.Name == "running")'
{
  "Code": 16,
  "Name": "running"
}
{
  "Code": 16,
  "Name": "running"
}