シェルのワンライナーの再利用性を高めるたった一つの方法


2011年 12月 01日

問題

シェルはお友達です。
一見すると役に立たないように思えるコマンドでも、
組み合わせ次第で複雑な処理をこなすための道具になります。

例えば

  • head – ファイルの先頭10行を出力する。
  • cut – ファイルの各行のうち特定の部分を選んで出力する。
  • shasum – SHA-1 ハッシュ値を出力する。

という、一つ一つでは大して役に立ちそうにないコマンドも、

head /dev/urandom | shasum | cut -f 1 -d ' '

このように組み合わせることで「ランダムなパスワードを自動生成する」という偉業を達成することができます。

シェルをある程度使っていると上記のようなワンライナーをしばしば入力することがあります。
覚え易いものや短いワンライナーなら即席で入力しても構わないのですが、
先ほどの例のようなものになると少々入力するのが面倒です。
そこで役に立つのがコマンドラインの入力履歴です。
入力履歴があれば、例えば
三か月前に試行錯誤の末に編み出した git filter-branch でリポジトリを消毒するワンライナー
であっても、簡単に再実行することができます。

入力履歴は大変便利なのですが、
こと検索においては欠点があります。
コマンド一つ一つが汎用的で小粒なために、
いざ検索しようとすると適切なキーワードが閃きづらい ということです。
パスワード生成の例では shasum が比較的出現頻度の低いコマンドなので、
これをキーワードにして検索すればまだ見つけ易い方ではありますが、
shasum を含む応用例は他にもあるため、
一発で目的のワンライナーに辿り着けることは多くありません。
素早く目的のワンライナーを見つけ出すにはどうすればよいのでしょうか。

解答

ワンライナーを実行する際にタグ代わりにコメントを添えます。

シェルスクリプトを書く場合は適宜コメントを書きますが、
対話的にコマンドを入力する場合でもコメントを書くことは可能です。
例えば以下のようなワンライナーを実行しても、最後の #password はコメントなので単に無視されます:

head /dev/urandom | shasum | cut -f 1 -d ' ' #password

このような形でワンライナーを実行して入力履歴に保存しておけば、
このコメントをキーにして即座に目的のワンライナーを探し出すことができます。
対話的にシェルを利用する場合に敢えてコメントを書くケースはまずないでしょうし、
コマンドに対する引数として '#foo' のようなものを指定するケースもごく稀でしょうから、
かなりの高精度で検索が可能です。

補足

実際には対話シェルでコメントが使えるかどうかは設定によります。

また、入力履歴を有効活用する場合は記録されるコマンド数の上限をなるべく高くしておくとよいでしょう:

HISTSIZE=1000000
HISTFILESIZE=$HISTSIZE  # bash の場合
SAVEHIST=$HISTSIZE  # zsh の場合