bashのキーバインド(キーボードショートカット) まとめ - readlineとbind、ついでにstty編

復習がてらまとめてみた。今さら感たっぷりでたぶん100番煎じぐらいだけど。きっかけは単語単位でカーソルを移動させる(M-f,M-b)方法が知りたかっただけなんだけど。せっかくなのでどこで、どういう風にキーバインドが割り当てられているかを調べた。

versionはdebian4のbash 3.1.17。

readlineとbind(組み込みコマンド)

man bashreadlineとbindの項目参照。readlineはシェルの入力を処理するライブラリ。bashは組み込みのコマンドでreadlineの割り当て設定確認/設定変更が出来る。

端末ラインのキーバインド

さて、さっそくbashキーバインド…の前に、シェルとは別の端末のキーバインドもまとめておく。bashとは直接関係ないけど、端末をCLIの操作をキーバインドで行うという意味では、ほぼ同じなので。
有名なのはプロセスを割り込むC-c(interrupt)や、中断するC-z(suspend)。出力を停止するC-s(stop)などなど。シェルの機能ではないので、bashだけでなく他のシェル(sh、cshzshなど)でも同じように動く。はず。

設定確認
$ stty -a

詳細はman 1 stty。

主なキーバインド
キーバインド name 説明
C-c intr 割込みシグナルを送る(プロセス終了) # kill -2, kill -INT
C-\ quit 中止シグナルを送る(プロセス中止) # kill -3, kill -QUIT
C-z susp 停止シグナルを送る(プロセス中断) => fg、bgで再開できる # kill -STOP
C-d eof EOFを入力する(ファイルの終わり)
C-u erase カーソルより前にある文字を削除
C-w werase 直前の単語を削除
C-s stop 画面への出力を停止する
C-q start C-sで停止していた画面への出力を再開する

C-sの出力停止
一見すると端末がハングしたように見える。が、出力が止まっているだけで端末への入力は生きている。コマンドももちろん実行される。
bashではC-sは履歴のインクリメンタルサーチに割り当てられているけど、sttyでは画面の停止に割り当てられているので、こちらが優先される。個人的にはこの停止の機能、うっかり混乱してしまうだけのいらない子だと思っているので無効にしています。Windowsの癖でファイルを上書きしようとして、うっかりこれを押してまごまごしたりするし。

C-sによる画面の停止を無効にする
参考: http://www.itmedia.co.jp/help/tips/linux/l0612.html
.bashrcあたりに

stty stop undef

と書いておくと、次回ログイン時から自動的に反映。

bashキーバインド

閑話休題。keymapはデフォルトのemacsとする(なのでemacs使いの人にとっては大半は常識の内容)。ちなみにman bashの中ではキーバインドではなくてキーシーケンスと説明されていた。

組み込みコマンドのbind -sでreadlineのマクロ、bind -pでreadlineの関数が表示される。そのうち、良く使うもの/頭に入れておけば便利かもしれないものをまとめてみた。複数キーバインドが割り当てられている関数は、基本的に簡単なものだけ書く。例えば、1つ前の単語に戻るキーバインドはM-d以外にもM-[1;5Dという呪文のようなものもあるけどこれは省く。

$ bind -p | egrep -v '^#|self-insert|do-lowercase-version|digit-argument'

の結果から抽出。Ctrlは文字、Meta(Alt、Esc)は単語単位になってることが多い?

コマンド実行
キーバインド readlineの関数名 説明
C-g abort Ctrl、Alt、Escなどの入力を中止
C-j accept-line Enter
C-m accept-line Enter
C-o operate-and-get-next Enterして、現在の入力内容を次の入力に利用。連続して同じコマンド実行するときとか
C-x C-e edit-and-execute-command エディタを起動して実行するコマンドを入力 *1
カーソル移動系
キーバインド readlineの関数名 説明
C-a beginning-of-line 行頭に移動 # Home
C-e end-of-line 行末に移動 # End
C-b backward-char 1文字戻る # ←
C-f forward-char 1文字進む # →
C-n next-history 次の履歴を表示 # ↓
C-p previous-history 前の履歴 # ↑
M-f forward-word 次の単語に移動
M-b backward-word 前の単語に移動
M-< beginning-of-history 履歴の先頭を表示
M-> end-of-history 履歴の最後を表示
文字入力、削除、貼り付け
キーバインド readlineの関数名 説明
C-h backward-delete-char 直前の1文字を削除 # BackSpace
C-d delete-char 直後の1文字を削除 # Delete
C-w unix-word-rubout 直前の1単語を削除(単語境界は空白類)
MC-h backward-kill-word 直前の1単語を削除
M-d kill-word 直後の1単語を削除
C-u unix-line-discard カーソル以前の文字を削除 # パスワード間違ったときなどに
C-k kill-line カーソル以降の文字を削除
C-y yank 削除,killした単語を貼り付け
C-t transpose-chars 直前の文字と、その前の文字を入れ替える
検索、補完
キーバインド readlineの関数名 説明
C-r reverse-search-history 履歴を後方に(遡って)インクリメンタルサーチ
C-s forward-search-history 履歴を前方にインクリメンタルサーチ *2
C-i complete コマンド、引数など。適した単語を補完 # Tab
M-! complete-command コマンドを補完
M-/ complete-filename filenameを補完
M-@ complete-hostname hostnameを補完 # /etc/hosts から?
M-~ complete-username usernameを補完 # /etc/passwd から?
M-$ complete-variable シェル変数を補完
M-. insert-last-argument 直前のコマンドの最後の引数を挿入
C-x* glob-expand-word globを展開する
M-* insert-completions 補完対象の単語を引数に挿入
その他
キーバインド readlineの関数名 説明
C-l clear-screen ターミナルをクリア # clearコマンド
M-l downcase-word 直後の単語を大文字に変換
M-u upcase-word 直後の単語を大文字に変換
C-xC-r re-read-init-file .inpurtc?をreload
C-xC-v display-shell-version version表示

こんなもん?

readlineの割り当てを変更する

  • .inputrcに書いておく
  • bindコマンドで割り当てる
  • bind -f filename (.inputrc書式) から読み込む

man bashより。

bind [-m keymap] -x keyseq:shell-command
bind [-m keymap] [-q function] [-u function] [-r keyseq]
bind [-m keymap] -f filename
bind [-m keymap] keyseq:function-name
  (中略)
  -l           readline関数の名前を全てリスト表示します。
  -p           readlineの関数の名前と割り当てを表示します。表示は、再び読み込みできる形式で出力されます。
  -P           readlineの関数の現在の名前と割り当てをリスト表示します。
  -v           readlineの変数名と値を表示します。表示は、再び読み込みできる形式で出力されます。
  -V           readlineの現在の変数名と値をリスト表示します。
  -s           readlineのマクロに割り当てられたキーシーケンスと、マクロが出力する文字列を表示します。
                  表示は、再び読み込みできる形式で出力されます。
  -S           readlineのマクロに割り当てられたキーシーケンスと、マクロが出力する文字列を表示します。
  -f filename     キー割り当てを filename から読み込みます。
  -q function  指定された function を呼び出すキーを問い合わせます。
  -u function  指定された function に割り当てられているキーの割り当てを全て取り消します。
  -r keyseq    keyseq に対する現在の割り当てを削除します。
  -x keyseq:shell-command  keyseq が押されるたびごとに、 shell-command が実行されるようにします。

コマンドで直接割り当てるときはquoteしないといけない。

$ bind '"\C-x\C-h": backward-kill-line'
$ bind -p | grep '\\C-x\\C-h'
"\C-x\C-h": backward-kill-line
  • マクロ

C-oで" > output"を挿入する。

$ bind '"\C-o": " > output"'
$ bind -s | grep output
"\C-o": " > output"
  • 任意のコマンドを割り当てる

C-xC-sでsshログインを実行。ただし、割り当てたコマンドはbindで確認できないぽい?

$ bind -x '"\C-x\C-s": ssh user@gateway.example.com'

まぁ良く使うコマンドならaliasしとけばいいので、わざわざbindしなくてもいいんだけど。超頻繁に入力するコマンドならキーバインドに割り当てるのもありかも?


入門bash 第3版

入門bash 第3版

*1:ちょっとしたfor,whileループを書くときに便利?

*2:stty stop undefしてる必要あり