Tera Term 等の端末を複数同時に立ち上げて作業したり、 screen にて複数の仮想端末を同時並行で操作する際、コマンド実行履歴が端末間で共有できなくて困る事が多々あります。「さっきのfindコマンドをもう一度... 引数どう書くんだっけなぁ... あ、確かコマンド履歴にあったはずだなぁ... ちっ、それはあっちの端末の履歴だったか」みたいな。zshには端末間のコマンド履歴を常に同期できる'SHARE_HISTORY' なるオプション(*1)があって素敵なのですが、同じことを bash で実現する方法を調べたのでご紹介。 (*1) zshの同機能について詳しくはITmedia記事 " 豪傑の三種の神器【後編】 " を参照の事

不具合) 通常設定のbashで困る事

1. 複数端末間でコマンド履歴の共有ができない

同時に立ち上げている端末間で履歴の共有ができなくて不便に感じることがある。

2. 最後に閉じた端末の履歴しかファイル保存されない

コマンド履歴は端末を閉じた際に ~/.bash_history ファイルに保存されますが、毎回"上書き保存"するため、最後に閉じた端末の履歴しか保持されなくて困る。



[クリックで拡大]

※後者の問題だけなら ~/.bashrc に 'shopt -s histappend' という1行を追加すれば解決は可能。

解決策) bashでコマンド履歴を共有する方法

以下の記述を ~/.bashrc 等に追記することで上記問題がすべて解決します。

.bashrcファイル追記内容:

function share_history {

history -a

history -c

history -r

}

PROMPT_COMMAND='share_history' shopt -u histappend export HISTSIZE=9999

変更を保存した上で、すべてのbash端末を立ち上げなおせば有効になります。これにより、以下のようなロジックにて、コマンド履歴が複数端末間で常に同期されるようになります。



[クリックで拡大]

基本的な原理は、各端末にて何かしらのコマンドを実行する度に、

1) .bash_history ファイルに1行追記した上で

2) .bash_history を端末自身の履歴として読み込みなおす

という処理が毎回裏で自動実施される事で同期がとれる仕組みになっています。また各端末を閉じた際にはあいかわらず .bash_history ファイルへの"上書き保存"が発生しますが、常に内容の同期が取れているため毎回同じ内容が書き出されるだけなので問題ありません。

詳細) 追記内容の意味解説

各行の意味は以下の通りです:

function share_history { # 以下の内容を関数として定義

history -a # .bash_historyに前回コマンドを1行追記

history -c # 端末ローカルの履歴を一旦消去

history -r # .bash_historyから履歴を読み込み直す

}

PROMPT_COMMAND='share_history' # 上記関数をプロンプト毎に自動実施

shopt -u histappend # .bash_history追記モードは不要なのでOFFに

export HISTSIZE=9999 # 履歴のMAX保存数を指定

man bash を探ると、historyコマンドのオプションには他にも 'history -n' - 差分のみを .bash_history から読み込み直す - なんて機能もありましたが、zshと違って行ごとにタイムスタンプを持たない為期待通りな動作はしませんでした。という訳でやむを得ず 'history -c' と 'history -r' を組み合わせて、履歴を毎回再読み込みさせている次第です。

注意点) HISTSIZEが大きいとレスポンスが重くなるかも

'HISTSIZE=履歴MAX保存数' にてさかのぼれるコマンドの数を指定できますが、ヘビーユーザーの中には数十万-数百万行とか指定している方もいると思われます。前述の通り、今回の手法は「プロンプトにて何かしらのコマンドを実行する度に、裏で .bash_history ファイルを再度読み込み直す」 事をしているため、HISTSIZEがあまりに大きいとbashのレスポンスが遅くなると思われます。どれくらい実用に耐えうるか、僕の Pentium M 1.2GHz + RAM 256MB な colinux/Debian 環境で試してみたところ、

HISTSIZE=300000 (30万)で、プロンプト表示毎に「んっ」と一瞬もたつく程度

でした。screenの場合も同程度。もちろんHISTSIZEを数千-数万件に抑えればレスポンスは向上します。これを是とするかどうかは各々で判断ください。いまいちだと感じた場合は冒頭で触れた zsh の利用をオススメします。

任意の環境でレスポンスを気軽に試せるよう、ダミーなコマンド履歴で埋め尽くされた .bash_history ファイルを生成することのできるperlスクリプトを用意しました。以下のように実行することで同階層に任意の行数の .bash_history ファイルが生成されます。

$ perl make_dummy_history.pl 100000 →同階層に履歴数10万件の .bash_history ファイルを出力

中身はてんで出鱈目な内容ですが、レスポンスを計るだけなら充分使えます。これを ~/.bash_history ファイルとして置き換えて、.bashrc 内のHISTSIZEに任意の保存数を指定した上で端末を立ち上げ直してください。Enterキーを押す度にレスポンスを確かめる事ができます。

参考情報