🐷

CLツールは標準入力と標準出力を意識して作りたい話

2023/05/28に公開

こんにちは。
みなさん CLI はどんな時に使っていますか?cdvilsなどを実行したい時ですか?
エンジニアならみんな使う CLI ですが、何か困り事がある場合に自分でツールを実装して使いたい時もあるかもしれません。

この記事はそんな時に少し役立ちそうな話をします。

Unix ツールを用いてファイル内を分析する

本題を始める前にまずは CL ツールを使った簡単な分析の例を見てみます。

以下のようなローカル環境で立ち上げた nginx のアクセスログを用意しました。
*一部のみです。本当はもっと続いています。

172.18.0.1 - - [27/May/2023:16:07:00 +0000] "GET /api/user/me HTTP/1.1" 401 39 "-" "PostmanRuntime/7.32.2" "-"
172.18.0.1 - - [27/May/2023:16:07:00 +0000] "GET /api/user/me HTTP/1.1" 401 39 "-" "PostmanRuntime/7.32.2" "-"
172.18.0.1 - - [27/May/2023:16:07:16 +0000] "POST /api/auth HTTP/1.1" 200 187 "-" "PostmanRuntime/7.32.2" "-"
172.18.0.1 - - [27/May/2023:16:07:16 +0000] "POST /api/auth HTTP/1.1" 200 187 "-" "PostmanRuntime/7.32.2" "-"
172.18.0.1 - - [27/May/2023:16:07:23 +0000] "GET /api/image_files HTTP/1.1" 200 132 "-" "PostmanRuntime/7.32.2" "-"
172.18.0.1 - - [27/May/2023:16:07:23 +0000] "GET /api/image_files HTTP/1.1" 200 132 "-" "PostmanRuntime/7.32.2" "-"
.
.
.

アクセスログは大きくなりがちです。今回はローカル環境で用意したので、ファイルサイズもそこまで大きくありませんが、実運用されているサービスのアクセスログは膨大になっていることも多いでしょう。
そんなアクセスログを Unix ツールを用いれば数秒で分析することができます。

シェルで以下のようなコマンドを叩いてみます。

% cat path/to/access.log |
pipe> awk '{print $7}' |
pipe pipe> sort |
pipe pipe pipe> uniq -c |
pipe pipe pipe pipe> sort -r -n |
pipe pipe pipe pipe pipe> head -n 5

これはリクエスト先のエンドポイントごとにカウントします。
結果は以下の通りです。

8 /api/user/me
8 /api/image_files
8 /api/auth

各コマンドの仕様等が知りたい場合は $ man ツール名 などとすれば各ツールの情報が確認できるので、ぜひみてみてください。ここでは細かい解説は行いません。

上記のコマンドの実行時間は1秒以下です。もちろんファイルがかなり小さいことが関係していますが、これがギガファイルだったとしても Unix ツールは数秒以下で処理します。

Unix 哲学

先述したパイプでツールを繋いでいく考え方は、Unix 哲学と呼ばれています。Unix 哲学とは Unix の開発者やユーザーの間で広まった設計原則で、以下の4つが定義されています。

  1. それぞれのプログラムが1つのことをうまくこなすように。新しい仕事をするために、新しい「機能」を追加して古いプログラムを複雑にするのではなく、新しいプログラムを構築する。
  2. すべてのプログラムの出力が、まだ見ぬ別のプログラムの入力になること。出力に余計な情報を入れないように。厳密に列挙された入力形式やバイナリ形式は避ける。インタラクティブな入力にこだわらない
  3. ソフトウェアはもちろんOSであっても、早期に、理想としては数週間以内に試せるよう設計・構築する。不器用な部分は躊躇なく捨てて作り直すように
  4. 回り道をしても、使い終わった後に捨てることになっても、プログラミングの作業を軽減するためには、お手伝いさんではなくツールを使う

出典:wikipedia

4つの中からこの記事の中で意識したいのは、2です。
少なくとも先述したツール catawksortheaduniqは標準入力から値を受け取り、結果を標準出力します。
これをパイプで繋ぎ Unix ツールを連携させ、高速に便利にファイルを分析します。

独自実装のツールも Unix ツールのパイプラインに参加させる

ここまで読まれた方は何が言いたいのかわかるかもしれませんが、独自で実装したツールも標準入力からデータを受け取り、結果を標準出力したいということです。
つまり、ツール内でファイルを読み込んだり、結果を別ファイルに書き込んだりしないということです。
どうしても結果がファイルで欲しい場合はリダイレクトすれば良いだけなので、困ることはありません。

% cat path/to/access.log |
pipe> awk '{print $7}' |
pipe pipe> sort |
pipe pipe pipe> uniq -c |
pipe pipe pipe pipe> sort -r -n |
pipe pipe pipe pipe pipe> head -n 5 >> analysis_results.txt ← >> でファイルへリダイレクト

こうすることにより、自分で開発したツールも Unix のパイプラインに参加させることができ、より柔軟に実装・使用できるかもしれません。

Unix ツールの強力さを知り、楽しくツール作成していきたいですね。

参考

Unix 哲学

データ思考アプリケーションデザイン
この記事の内容はほとんど上記の書籍に書いてあります。もっと詳しく書いてあるので、興味があればぜひ読んでみてください。

余談

独自ツールを実際に実装して、Unix ツールと連携させた経験が今のところないので、Tips ぐらいの感じで自分の中にとどめています。その時が来たらここに書いた内容を生かしていきたいですね。

Discussion