Linux(Bash)で簡単コマンド履歴検索

ターミナルでhistoryコマンドを実行すると、過去に実行したコマンドの一覧を見ることができて便利です。特定のコマンドを抽出したい場合は、次のようにgrepコマンドと組み合わせます。

$ history | grep ssh

結果はこのような感じで返ってきます。

 14  ssh example.com
 15  ssh test@example.com
 121 ssh test@example.jp

表示されたコマンドを再度実行する場合は、コマンドをコピペしても良いですが、一緒に表示される番号の頭に「!」をつけて

$ !121

としても、コマンドを再度実行することができます。

これでも十分便利なのですが、次の方法を使うと、過去のコマンド履歴を使って、入力中のコマンドを補正することができます。

ホームディレクトリに次のファイルをコピーし、

$ cp /etc/inputrc ~/.inputrc

次の内容を追記して保存します。

"\e[A":history-search-backward
"\e[B":history-search-forward

これで、コマンドの入力中にキーボードのカーソルの「↑」を押すと、それまで入力したコマンドに前方一致する過去のコマンドの履歴を一つずつ確認することができます。また、履歴を遡った後に「↓」を押すと、一つ直近のコマンドに戻ります。

プロンプトの表示の変更

表示内容の変更

PS1という環境変数の値を変更することで、Bashのプロンプトの表示を変更することができます。例えば

[user@host:/path/to/current_directory]$

という表示にしたければ

$ export PS1="[\u@\H:\w]$ "

と設定します。ただ、毎回このコマンドを入力するのは大変なので、ホームディレクトリにある.bashrcに書き込んで、ログイン時に自動的に設定されるようにしましょう。

$ vim ~/.bashrc

export PS1="[\u@\H:\w]$ "

PS1の設定値の中で使用できる特殊文字は以下のとおりです。

\a ASCIIのベル文字 (07)
\d “曜日 月 日” という形式の日付 (例: “Tue May 26”)
\D{format} formatstrftime(3)に渡され、その結果がプロンプト文字列に挿入される。formatが空の場合には、ロケールで指定された時刻表記になる。(ブレースは必要)
\e ASCIIのエスケープ文字 (033)
\h ホスト名のうち最初の「.」までの部分
\H ホスト名
\j シェルによって現在管理されているジョブの数
\l シェルの端末デバイスのベース名
\n 改行
\r 復帰
 \s シェルの名前。つまり$0のベース名 (最後のスラッシュ以降の部分)
 \t 24 時間制のHH:MM:SS形式の現在の時刻
\T 12 時間制のHH:MM:SS形式の現在の時刻
\@ 12 時間制のam/pm形式の現在の時刻
\A 12 時間制のHH:MM形式の現在の時刻
\u 現在のユーザのユーザ名
\v bashのバージョン (例: 2.00)
\V bashのリリース。バージョンにパッチレベルを加えたもの (例 : 2.00.0)
\w 現在の作業ディレクトリ。$HOMEの部分はチルダに短縮される。(PROMPT_DIRTRIMの値が適用される。)
\W 現在の作業ディレクトリのベース名$HOMEの部分はチルダに短縮される。
\! このコマンドの履歴番号
\# このコマンドのコマンド番号
\$ 実効UIDが0の場合に#、それ以外の場合は$
\nnn 8進数nnnに対応する文字
\\ バックスラッシュ
\[ 非表示文字のシーケンスの開始。これを使うと、プロンプト中に端末の制御シーケンスを埋め込むことができる。
\] 非表示文字のシーケンスを終了する。

色の変更

また、色を変えることもできます。色を変えたい文字列を\[\e[<色>m\]と[\e[m\]で囲みます。例えば、ユーザ名を赤くしたい場合は、

$ export PS1="[\[\e[31m\]\u\[\e[m\]@\H:\w]$ "

とします。色はANSIカラーシーケンスに従います。

色のパターン

30
31
32
33 黄色
34
35
36 水色
37

 

また、色の前か後ろに、セミコロンで区切って一桁の数字を入れることで、文字の装飾を指定することができます。

$ export PS1="[\[\e[31;1m\]\u\[\e[m\]@\H:\w]$ "

装飾のパターン

0 なし
1 太字
4 下線
5 点滅
7 反転

 

私のお気に入りは次の設定です。

$ export PS1="[\[\e[01;31m\]\u\[\e[m\]@\[\e[01;33m\]\H\[\e[m\]:\[\e[01;36m\]\w\[\e[m\]]$ "

この場合、プロンプトはこんな感じになります。ps1

Bashで終了ステータスよる条件分岐

Bashにおいて、前に実行されたコマンドの終了ステータスは「$?」で取得することができます。

$ echo Hello
Hello
$ echo $?
0

終了ステータスは各コマンドによって定義されており、0から255までの値をとることができます。慣習的に、コマンドが正常終了した場合は0が返され、異常終了の場合はその理由に応じて0以外の数字が返されます。上記の例であれば、echoコマンドで正しくHelloが出力され、正常に終了したため、終了ステータスは0となります。

シェルスクリプトにおいては、この終了ステータスを元に条件分岐をさせる場合があります。例えば、あるコマンドを実行して、それが正常終了しなかった場合にエラーメッセージを画面に表示させるには、以下のように行います。

#!/bin/bash

command

if [ $? -ne 0 ]; then
    echo "Error occurred while executing 'command'"
fi

複数の終了ステータスに応じて条件分岐させる場合には注意が必要です。例えば、以下のプログラムは正しく動きません。

#!/bin/bash

command

if [ $? -eq 0 ]; then
    echo "Success"
elif [ $? -eq 1 ]; then
    echo "Failure: Exit status = 1"
elif [ $? -eq 2 ]; then
    echo "Failure: Exit status = 2"
else
    echo "Failure: Others"
fi

commandが正常終了した場合は、「Success」と正しく出力されますが、異常終了の場合は、終了ステータスに関わらず「Failure: Exit status = 1」が出力されてしまいます。これは、最初のif文の「[ $? -eq 0 ]」によって、$?に1が上書きされてしまうためです。「[]」は「test」コマンドの略式であり、引数の条件式が真の場合は0を、偽の場合は1の終了ステータスを返すため、今回のケースでは、$?が0以外の場合は常に1を返すことになります。この問題を避ける方法は単純で、以下のように、command終了後すぐに$?を別の変数に代入し、条件分岐にはその変数を利用するようにします。

#!/bin/bash

command
rc=$?

if [ $rc -eq 0 ]; then
    echo "Success"
elif [ $rc -eq 1 ]; then
    echo "Failure: Exit status = 1"
elif [ $rc -eq 2 ]; then
    echo "Failure: Exit status = 2"
else
    echo "Failure: Others"
fi

 

Top