• Windows Subsystem for Linuxガイド 第39回 Bashのヒストリ機能 その1「利用編」

今回より、ときどき、WSL自体ではなく、WSLあるいはLinuxを使う場合の基礎知識的な記事を入れることにする。これは、Windowsには慣れているものの、Linuxにはなじみのない読者を想定している。

bashには、実行したコマンドを記録し、あとから呼び出して利用するための仕組み「ヒストリ」機能がある。ヒストリの日本語訳としては「履歴」が充てられることが多いが、一般用語としての「履歴」もあるので、ここでは「ヒストリ」と表記する。

ヒストリ機能の使い方

ヒストリ機能は、実行が成功したコマンドを順次記録していく。注意するのは実行がエラーになったコマンドは記録されないことだ。こうして作られたコマンドのリストに対して、「キーボードによるコマンドの呼び出し」、およびbashの「履歴展開」機能の2つが利用できる。

前者は、PowerShellの履歴などと同じく、「↑」キーなどで以前に実行したコマンドを呼び出すもの。キーボードを使うヒストリ機能は1980年台に開発されたKornShell(ksh)に搭載され、その後一般的になった。なお、この場合、実行前にコマンドラインを修正することもできる。

後者は、コマンドラインに過去のコマンドや引数などを参照する記号を使うもの。例えばコマンドラインに「!!」と入力してエンターキーを押せば、「↑」とエンターキーを押したのと同じく、直前のコマンドを実行できる。この履歴展開の機能は、1970年台に開発されBSD系UNIXに搭載されたC Shell(csh)に採用され、bashはこれを引き継いだ。cshの作者の一人であるビル・ジョイによれば、Interlisp-Dのredoコマンドを参考にしたという。

(表01)は、bashの標準的なヒストリ関連のキーを示す。ディストリビューションやバージョンにより多少の違いが出る可能性があるものの、多くのディストリビューションのbashでは、これらのキーが使える可能性が高い。

  • ■表01

上下カーソルキーが2つあるのは、端末(コンソール・アプリケーション)のモードによって、同じ上下カーソルキーが生成するキーコードが異なるからである。また、一般的なLinuxのコンソールでは、Ctrl+Sは、sttyコマンドでstopキーとして定義されているため、このキーを押すと、先にsttyの方で解釈されることになり、bash/readline側にキーコードが渡らない。ヒストリ機能に限らず、bashのコマンドラインで、Ctrl+Sを利用したい場合には、sttyコマンドでCtrl+Sの割り当てを取り消す必要がある(解説は次回)。

それぞれのキーに割り当ててある機能は、表右側の関数名で決まる。それぞれ、readlineまたはbashが提供している関数(機能)である。それぞれの関数の解説は、readlineまたはbashのmanページにある。WSLディストリビューションにmanがインストールされているなら、それぞれ「man readline」または「man bash」でmanページが開く。あるいは、bashやreadlineのキーワード(表の提供元参照)とともに関数名をインターネット検索してもよい。

もっとも、簡易には、カーソルキーの上下でイベントを順次表示させ、必要なところでエンターキーで実行する。あるいは、Ctrl+Rキーを押し、過去のコマンドが含む文字を入れていくことで補完が進む。再度Ctrl+Rを打鍵すると、同じ文字で補完できる別のイベントが表示できる。これを使うことで、イベントの検索が可能だ。

Esc nとEsc pは、Escキーを押したのちnまたはpキーを押す。コマンドラインにコロン「:」が表示され、その後、検索文字列を入力して、エンターキーを押せば、ヒストリ機能の検索が行われる。Esc nならば、前方(過去から現在方向)、Esc pならば、後方(現在から過去方向)に検索が行われる。

Esc Tabキーは、コマンドラインにユーザーが入力した文字を使って、ヒストリのイベントによる補完や補完候補表示を行う。たとえば、過去に「echo」コマンドを含むイベントがあれば、コマンドラインに「ec」を入力したあと、Esc pで「echo」が候補として表示される。ただし、補完単位はスペースで区切られたワードに限られる。

Esc ^は、入力中のコマンドに入れたヒストリ展開(後述)を強制的に展開するコマンドだ。これを使うことで、ヒストリ展開がどのように行われるのかを見てからコマンドを実行させることが可能になる。

ヒストリ展開

ヒストリ展開は、コンピュータの利用が機械式プリンタとキーボードを組み合わせていた「機械式端末装置」が、主に使われていた時代のものだ。出力がプリンタとなるため、上カーソルキーのようにコマンドラインを次々と書き換えていくことができない。このため、打鍵数や出力文字数が少ない方法でのヒストリ実行が考えられた。

たとえば、同一のファイルに対して、複数のコマンドを順次適用する場合がある。たとえば、ファイル編集コマンド(エディタ)とコンパイルコマンドなどを繰り返し実行する場合などだ。このようなとき、


vi ~/source/prog01.c
cc !*

とすることで、2つ目のccコマンドに対して1つ目と同じ引数を与えることが可能になる。長いファイルパスなどを再度入力する必要がない。

bashのヒストリ展開は、対象のイベントを指定する「イベント指示子」、「単語指示子」、「修飾子」の2つをコロン「:」で区切って指定する。(表02)にイベント記述子、単語指示子、修飾子の一覧を示す。「単語指示子」、「修飾子」は省略も可能である。指定パターンとしては、以下の4つのパターンがある。


① {イベント指示子}
② {イベント指示子} ":" {単語指示子}[":" {修飾子}]
③ "!:" {単語指示子}[":" {修飾子}]
④ "!"{^、$、*、-、%で始まる単語指示子}[ ":" {修飾子}]

①は、イベント指示子のみでヒストリを指定して実行するもの。たとえば、!!で直前のコマンドが、!-2でその前のコマンドを指定できる。

②は、イベントを指定し、そこから特定の単語を抜き出すもの。このとき、修飾子を使って単語を加工(たとえば、パスから親ディレクトリ名のみを取り出す)が行える。

③は、直前のコマンドを対象とした場合、単語指示子および修飾子(省略可能)が適用できる。

④は、③の特殊な場合で、単語指示子が「^」、「$」、「*」、「-」、「%」の4文字で始まる場合に限り、「!」の後ろのコロンを省略できる。これに修飾子を適用することもできる。代表的な指定方法として「!*」(直前のコマンドの引数すべて(コマンド以外すべて)、「!$」(直前のコマンドにある最後の引数)などがある。

  • ■表02

CRTを使うターミナルがまだ普及していない頃に考えられたコマンドであり、打鍵数は最小にできる半面、どのような記法を使うか熟慮する必要がある。ただし、すべてのヒストリ展開を使う必要はなく、簡単な「!!」や「!*」などだけを使うところから始めるといいだろう。

なお、ヒストリキーの「Esc ^」を使うことで、入力したヒストリ展開文字を実行前に展開して表示することができる。

次回は、ヒストリに関する設定について解説する予定だ。

> Windows Subsystem for Linuxガイド 連載バックナンバー
https://news.mynavi.jp/tag/winsubsystem/