🐥

curlとjqコマンドを使って1ヶ月間に書いた記事を取得したい

2021/02/07に公開

はじめに

毎月のふりかえりをするときに、その月に書いた記事一覧を毎回調べてコピペしていたのですが、毎回これをするのはめんどくさいのでコマンド一発で取れるようにしたくてjqコマンドの使い方を調べてみました。

jqコマンドについて

jqコマンドはコマンドラインでJSONをパースできるツールです。
こちらの動画で知って使ってみました。

https://www.youtube.com/watch?v=-HohpQP-lwU&t=1747s

インストール

$ brew install jq

想定するレスポンス(仮)

実際に返ってくるJSONだと長いので、仮のものとして以下を想定してみます。
1月1日と1月31日、2月1日に公開した記事データ、という体です。

{
   "articles":[
      {
         "id": 1234,
         "title": "this is sample1",
         "published_at": "2021-01-01T00:48:26.091+09:00"
      },
      {
         "id": 1235,
         "title": "this is sample2",
         "published_at": "2021-01-31T00:48:26.091+09:00"
      },
      {
         "id": 1236,
         "title": "this is sample3",
         "published_at": "2021-02-01T00:48:26.091+09:00"
      },
   ]
}

通常は上のように整形された形でレスポンスされないのでいったん一行にしておきます。
一行にするのには、jqコマンドの-cオプションを使用するとできます。
man jqで調べてみるとcompact-outputの略みたいですね。

o --compact-output / -c:

By default, jq pretty-prints JSON output. Using this option will result in more compact output by instead putting each
JSON object on a single line.

$ echo '{
   "articles":[
      {
         "id": 1234,
         "title": "this is sample1",
         "published_at": "2021-01-01T00:48:26.091+09:00"
      },
      {
         "id": 1235,
         "title": "this is sample2",
         "published_at": "2021-01-31T00:48:26.091+09:00"
      },
      {
         "id": 1236,
         "title": "this is sample3",
         "published_at": "2021-02-01T00:48:26.091+09:00"
      }
   ]
}' | jq -c
{"articles":[{"id":1234,"title":"this is sample1","published_at":"2021-01-01T00:48:26.091+09:00"},{"id":1235,"title":"this is sample2","published_at":"2021-01-31T00:48:26.091+09:00"},{"id":1236,"title":"this is sample3","published_at":"2021-02-01T00:48:26.091+09:00"}]}

レスポンスを整形する

まず、単純にJSONを整形してキレイにしてみます。ここでは、-cオプションつける前の状態にするイメージです。
レスポンスを単純に整形するには.というフィルターを使います。

$ echo '{"articles":[{"id":1234,"title":"this is sample1","published_at":"2021-01-01T00:48:26.091+09:00"},{"id":1235,"title":"this is sample2","published_at":"2021-01-31T00:48:26.091+09:00"},{"id":1236,"title":"this is sample3","published_at":"2021-02-01T00:48:26.091+09:00"}]}' | jq '.'
{
  "articles": [
    {
      "id": 1234,
      "title": "this is sample1",
      "published_at": "2021-01-01T00:48:26.091+09:00"
    },
    {
      "id": 1235,
      "title": "this is sample2",
      "published_at": "2021-01-31T00:48:26.091+09:00"
    },
    {
      "id": 1236,
      "title": "this is sample3",
      "published_at": "2021-02-01T00:48:26.091+09:00"
    }
  ]
}

JSONのキーを指定して取り出す

.フィルターに続けてkey名を指定すると対応するvalueを取り出すことができます。
この辺はJavaScriptっぽいですね。.articlesを指定して記事一覧を取得しています。

$ echo '{"articles":[{"id":1234,"title":"this is sample1","published_at":"2021-01-01T00:48:26.091+09:00"},{"id":1235,"title":"this is sample2","published_at":"2021-01-31T00:48:26.091+09:00"},{"id":1236,"title":"this is sample3","published_at":"2021-02-01T00:48:26.091+09:00"}]}' | jq '.articles'
[
  {
    "id": 1234,
    "title": "this is sample1",
    "published_at": "2021-01-01T00:48:26.091+09:00"
  },
  {
    "id": 1235,
    "title": "this is sample2",
    "published_at": "2021-01-31T00:48:26.091+09:00"
  },
  {
    "id": 1236,
    "title": "this is sample3",
    "published_at": "2021-02-01T00:48:26.091+09:00"
  }
]

配列を取り出す

Array/Object Value Iteratorを使います。
これも配列でよくある[]を使えばよいです。

$ echo '{"articles":[{"id":1234,"title":"this is sample1","published_at":"2021-01-01T00:48:26.091+09:00"},{"id":1235,"title":"this is sample2","published_at":"2021-01-31T00:48:26.091+09:00"},{"id":1236,"title":"this is sample3","published_at":"2021-02-01T00:48:26.091+09:00"}]}' | jq '.articles[]'
{
  "id": 1234,
  "title": "this is sample1",
  "published_at": "2021-01-01T00:48:26.091+09:00"
}
{
  "id": 1235,
  "title": "this is sample2",
  "published_at": "2021-01-31T00:48:26.091+09:00"
}
{
  "id": 1236,
  "title": "this is sample3",
  "published_at": "2021-02-01T00:48:26.091+09:00"
}

条件を指定して絞り込む

jqコマンドでは条件を指定してデータを絞り込むことも可能です。
たとえば、published_atが2月のものだけ抜き出したい場合は、ビルトインのselectという関数を使います。
また、jqコマンドの引数内で|を使ってパイプすることもできます。

$ echo '{"articles":[{"id":1234,"title":"this is sample1","published_at":"2021-01-01T00:48:26.091+09:00"},{"id":1235,"title":"this is sample2","published_at":"2021-01-31T00:48:26.091+09:00"},{"id":1236,"title":"this is sample3","published_at":"2021-02-01T00:48:26.091+09:00"}]}' | jq '.articles[] | select(.published_at >= "2021-02-01")'
{
  "id": 1236,
  "title": "this is sample3",
  "published_at": "2021-02-01T00:48:26.091+09:00"
}

条件を複数にする

select内でandを使って条件を複数指定できます。
select(条件A and 条件B)というフォーマットで指定します。
1月の間に書かれた記事という条件を指定したかったので、published_at2021-01-01以上、published_at2021-02-01未満を設定しています。

$ echo '{"articles":[{"id":1234,"title":"this is sample1","published_at":"2021-01-01T00:48:26.091+09:00"},{"id":1235,"title":"this is sample2","published_at":"2021-01-31T00:48:26.091+09:00"},{"id":1236,"title":"this is sample3","published_at":"2021-02-01T00:48:26.091+09:00"}]}' | jq '.articles[]
| select(.published_at >= "2021-01-01" and .published_at < "2021-02-01")'
{
  "id": 1234,
  "title": "this is sample1",
  "published_at": "2021-01-01T00:48:26.091+09:00"
}
{
  "id": 1235,
  "title": "this is sample2",
  "published_at": "2021-01-31T00:48:26.091+09:00"
}

URLの形に整形する

上記をさらに|で繋げて、URL形式の文字列にしていきます。
ポイントは

  • 基本となる文字列を""で囲む
  • 文字連結は+を使う
  • 数値のままだと文字連結できないので、ビルトインのtostring関数を使う
$ echo '{"articles":[{"id":1234,"title":"this is sample1","published_at":"2021-01-01T00:48:26.091+09:00"},{"id":1235,"title":"this is sample2","published_at":"2021-01-31T00:48:26.091+09:00"},{"id":1236,"title":"this is sample3","published_at":"2021-02-01T00:48:26.091+09:00"}]}' | jq '.articles[]
> | select(.published_at >= "2021-01-01" and .published_at < "2021-02-01") | "https://sample.app/articles/"+(.id|tostring)'
"https://sample.app/articles/1234"
"https://sample.app/articles/1235"

さいごに

これで1ヶ月間に書いた記事URL一覧処理が取得できました。ただこのままだといくつか問題があります。

  • 日付の指定が文字列リテラルなので、毎回手動で変えないといけない
  • シェルを手動で実行しないといけない

このあと、AWSなりで実行できるようにしてSlackに通知してくれるようにしたい・・・!

参考

Discussion