コマンドラインがさらに便利になるfillinコマンドを作りました!

fillinというコマンドラインツールを作成しました。

コマンドの一部を変数化して、別の履歴に保存しておけるツールです。 ステージング環境と本番環境のように、同じコマンドで複数の環境を切り替えるのに便利です。

どうして作ったの

コマンド履歴って便利ですよね。 私はよくコマンド履歴からコマンドを選んで実行しています。 シェルに付属しているデフォルトの履歴を使っている方もおられるでしょうし、fzfやpecoのようなインタラクティブな絞り込みを行なっている方もいるでしょう。

私が一番困っていたのが、認証キーの扱いです。 webアプリを作っていてcurlで素早く確認するときに、認証キーやアクセストークンを打つことがあります。 アクセストークンのようなランダムな英数字は、fzfのようなfuzzy searchとかなり相性が悪いものです。 最近fzfに乗り換えてインターフェースは気に入っていたのですが、トークンを入れてcurlする癖を直さないといけないなぁと思っていました。

いや、トークンを直に打つなよ…っていうご意見はごもっともです。 ライブコーディングする前に履歴消さないといけませんし。 Basic認証ならば標準入力で指定できるんですけど、ヘッダーは (たぶん) できませんよね。 認証キーは何かしらの履歴には残っていて簡単に呼び出したいけど、シェルの履歴には入れたくない… この程度のことにシェルスクリプトを書くのも面倒だし、ファイルに一個ずつ保存していちいち展開するのもかわいくない…

トークンをコマンドに直接書きたくない以外にも、コマンドの一部を別管理したいと思うことはたくさんあります。 データベースに繋ぐ時、データベースのホスト名とデータベース名はセットで管理したいですよね。 awsコマンドのプロファイルだってシュッと切り替えて同じコマンドを実行したくなることもあります。

コマンドの一部を「変数」にして、それを「展開して実行」してくれるコマンドがあれば良いのではないか? シェルの履歴が汚れることはないし、履歴をfuzzy searchしてもおかしなことにはなりにくい。 変数に埋めた値の履歴をローカルに保存して矢印キーとかで呼び出せれば便利そう…

はい、それがfillinです。

brew install itchyny/fillin/fillin

または

go get -u github.com/itchyny/fillin

でインストールできます。

導入編

fillinコマンドの使い方はとても簡単です。 いつも打つコマンドにfillinとつけて、「変えたいところ」をテンプレートにしてあげるだけです。 例えば、次のように打ってみましょう。

 $ fillin echo {{message}}
message: 

messageは何かと聞かれました。適当に打ってみます。

message: こんにちは、世界!
こんにちは、世界!

こんにちは! fillinコマンドは、messageの場所をユーザーに入力してもらい、その値を埋めてコマンドを実行するだけです。

そうです、{{message}}というところを「埋めて (fill-in)」から実行する、それがfillinコマンドです。

もちろん変数はいくつも使うことができます。

 $ fillin echo {{foo}} {{bar}} {{baz}}
foo: 変数を
bar: こういうふうに
baz: 入力するよ
変数を こういうふうに 入力するよ

かわいい。

普段使っているコマンドをテンプレート化してfillinとつけるだけなので、例えば環境変数を含んだコマンドも実行できます。

 $ fillin LANG={{lang}} date
lang: en_US
Mon Jun 12 08:22:55 JST 2017
 $ fillin LANG={{lang}} date
lang: ja_JP
2017612日 月曜日 082252秒 JST

便利!

実践編

いつも打つコマンドの中で、ホスト名のように環境によって切り替えるところをテンプレート化することができます。

 $ fillin psql -h {{psql:hostname}} -U {{psql:username}} -d {{psql:dbname}}
[psql] hostname: localhost
[psql] username: example-user
[psql] dbname: example-db

psql (9.6.3)
Type "help" for help.

example-db=>

各値を入力して決定すると、いつものようにコマンドが実行されます。 入力した値はまとめて履歴に残るので、同じコマンドから上矢印キーで呼び出すことができます。

 $ fillin psql -h {{psql:hostname}} -U {{psql:username}} -d {{psql:dbname}}
[psql] hostname, username, dbname: localhost, example-user, example-db

もちろん、ステージング環境用、本番用のように複数の設定を残すことができます。 psql:という同じ「スコープ」を持つ変数は、組になって履歴を呼び出すことができるのが便利なところです。

webアプリのAPIの動作確認でcurlを使う人ならば、次のようにbase-urlaccess-tokenを管理することができます (認証方法はサンプルです)。

 $ fillin curl {{api:base-url}}/api/info -H 'Authorization: Bearer {{api:access-token}}'
[api] base-url, access-token: example.com, accesstokenabcde012345

この例でもapi:というスコープをつけたので、ホストと認証キーがステージングと本番でごっちゃになることはありません。

何が直交したデータなのかということを考えるのはとても大事なことです。 ローカルの環境、ステージング環境、本番環境によって、ベースURLと認証キーは異なります。 そして、API/api/info, /api/service, /api/account … といくつかあります (URLは適当です)。 どのAPIも、どの環境に対しても叩くことができます。 つまり環境とAPIのエンドポイントは直交した概念です。

「このAPIのエンドポイントにcurlする」ということはシェルの履歴に残します。 「ステージングの認証キーや本番のキー」といった情報は、fillinの履歴に残します。 これによって、シェルにn*m個の履歴が残ることなく、コマンド履歴を探すのが楽になります。 新しいAPIのエンドポイントを作ったときも、開発時にローカル環境に対して打っておけば、後は同じコマンドでステージング、本番と切り替えるだけで動作確認できます。

こういう話はデータベース、API開発以外にもたくさんあると思います。 例えばawsコマンドの--profile引数ですね。

 $ fillin aws --profile {{aws:profile}} ec2 describe-instances
[aws] profile: aws-profile-example

EC2 (など) に何をするか×アカウントのプロファイルが直交概念ですね。 他にも応用が効く考え方だと思うので、是非よい使い方を考えてみてください。

まとめ

コマンドには「どこに」「何を」するかの二軸があります。 「どのホストのどのポートに」「Redis CLIでログインする」とか、「AWSのどのプロファイルの管理している」「EC2のインスタンスを一覧する」、「ステージング環境 (あるいは本番環境) の」「APIを叩いてレスンポンスを調べる」といった具合です。 fillinを用いると、この2つをきれいに分離し、コマンド履歴の管理が簡単になります。

コマンドには「何をするか」を打ちます。

ホスト名、ベースURL、認証キー、プロファイルといった「環境 (どこに)」はfillinで切り替えます。

このように運用すると、コマンドを打つのがとても楽になります。 いや、楽になりそうです… 前の木曜にアイディアを思いついて、この土日でようやく動いたばかりなので、まだがっつりは使ってないんです… でも、きっと便利なはずなので、よかったら使ってみてください。 私もしばらくfillin運用すると思います。 沢山の人に使っていただくと私がとても喜びます。

実際に実行されたコマンドが履歴に残らないのは困る? ご安心ください。 fillinコマンドは実行したコマンドをタイムスタンプ付きで~/.config/fillin/.fillin.histfileに保存しています (この場所が適切なのかという話はありそうだけど、まぁとりあえず…)。 zshのコマンド履歴を真似して出力しているので、fillinをやめたいとなったら (そんな…><)、.histfilegrep -v fillinし、.fillin.histfile.histfileに追記しソートするといい感じになるはずです。 よかったですね。

宣伝

はてなでは、開発時に不便なことがあったらツールを自分で作って解消する、そんな情熱あふれるエンジニアを募集しています。

エンジニア以外にも様々な職種のご応募お待ちしております。

こちらの記事もどうぞ。私です。