zshのショートカットキーをbashへ合わせていく

前回までに、bashで使える便利なショートカットキーをまとめた。この流れでzshについて同じショートカットキーを揃えていこうと思う。

zshはbashとともに多機能なインタラクティブシェルとして使われている。最近のmacOSではzshがデフォルトのインタラクティブシェルだ。そのため、Linuxを使っているときはbash、Macを使っているときはzshという違いが発生することがある。

bashもzshも提供している機能はよく似ているのだが、使えるショートカットキーやデフォルトで割り当てられているショートカットキーが異なっている。そのため、同じシェルだと思ってショートカットキーを使うと、思ったように動作せずにストレスが溜まるのだ。

組み込みデバイスやアプライアンスでは、ライセンスの関係でbashではなくzshが使われることもある。しかし、Linuxディストリビューションはbashをデフォルトのインタラクティブとして使っていることが多い。

bashとzshという違いがあったとしても、可能な限り同じショートカットキーを使えるように設定しておけば、操作のストレスをある程度軽減できるようになる。そこで、本連載で取り上げたbashのショートカットキーと同じようなショートカットキーをzshで実現する設定を探してみよう。

zshのキーバインドはzshzleが担当

zshでは「bindkey」という組み込みコマンドでキーバインドを変更する。このコマンドは、何も設定しないと次のように現在設定されているショートカットキーを表示する。

% bindkey
"^@" set-mark-command
"^A" beginning-of-line
"^B" backward-char
"^D" delete-char-or-list
"^E" end-of-line
"^F" forward-char
"^G" send-break
"^H" backward-delete-char
"^I" fzf-completion
"^J" accept-line
"^K" kill-line
"^L" clear-screen
"^M" accept-line
"^N" down-line-or-history
"^O" accept-line-and-down-history
"^P" up-line-or-history
"^Q" push-line
"^R" fzf-history-widget
"^S" history-incremental-search-forward
"^T" fzf-file-widget
"^U" kill-whole-line
"^V" quoted-insert
"^W" backward-kill-word
"^X^B" vi-match-bracket
"^X^F" vi-find-next-char
"^X^J" vi-join
"^X^K" kill-buffer
"^X^N" infer-next-history
"^X^O" overwrite-mode
"^X^U" undo
"^X^V" vi-cmd-mode
"^X^X" exchange-point-and-mark
"^X*" expand-word
"^X=" what-cursor-position
"^XG" list-expand
"^Xg" list-expand
"^Xr" history-incremental-search-backward
"^Xs" history-incremental-search-forward
"^Xu" undo
"^Y" yank
"^[^D" list-choices
"^[^G" send-break
"^[^H" backward-kill-word
"^[^I" self-insert-unmeta
"^[^J" self-insert-unmeta
"^[^L" clear-screen
"^[^M" self-insert-unmeta
"^[^_" copy-prev-word
"^[ " expand-history
"^[!" expand-history
"^[\"" quote-region
"^[\$" spell-word
"^['" quote-line
"^[-" neg-argument
"^[." insert-last-word
"^[0" digit-argument
"^[1" digit-argument
"^[2" digit-argument
"^[3" digit-argument
"^[4" digit-argument
"^[5" digit-argument
"^[6" digit-argument
"^[7" digit-argument
"^[8" digit-argument
"^[9" digit-argument
"^[<" beginning-of-buffer-or-history
"^[>" end-of-buffer-or-history
"^[?" which-command
"^[A" accept-and-hold
"^[B" backward-word
"^[C" capitalize-word
"^[D" kill-word
"^[F" forward-word
"^[G" get-line
"^[H" run-help
"^[L" down-case-word
"^[N" history-search-forward
"^[OA" up-line-or-history
"^[OB" down-line-or-history
"^[OC" forward-char
"^[OD" backward-char
"^[P" history-search-backward
"^[Q" push-line
"^[S" spell-word
"^[T" transpose-words
"^[U" up-case-word
"^[W" copy-region-as-kill
"^[[200~" bracketed-paste
"^[[A" up-line-or-history
"^[[B" down-line-or-history
"^[[C" forward-char
"^[[D" backward-char
"^[_" insert-last-word
"^[a" accept-and-hold
"^[b" backward-word
"^[c" fzf-cd-widget
"^[d" kill-word
"^[f" forward-word
"^[g" get-line
"^[h" run-help
"^[l" down-case-word
"^[n" history-search-forward
"^[p" history-search-backward
"^[q" push-line
"^[s" spell-word
"^[t" transpose-words
"^[u" up-case-word
"^[w" copy-region-as-kill
"^[x" execute-named-cmd
"^[y" yank-pop
"^[z" execute-last-named-cmd
"^[|" vi-goto-column
"^[^?" backward-kill-word
"^_" undo
" "-"~" self-insert
"^?" backward-delete-char
"\M-^@"-"\M-^?" self-insert
%

この出力は、bashにおける「bind -p」の出力によく似ている。しかし、キーの記述方法が少々異なっていることに注意が必要だ。「ESC」は「^[」と表記され、「Ctrl」は「^」と表記されている。

bashの場合は「readline」というソフトウエアがこの部分の処理を担当していたが、zshでは「zshzle」と呼ばれるzshのコマンドラインエディタがこの部分を担当している。そのため、bindkeyの使い方などはzshzleのオンラインマニュアルにまとまっている。「man zshzle」で読めるので、基本的にはこのマニュアルを参考にしながら設定方法を模索していくことになる。

「man zshzle」の出力サンプル

前回までは、bashのショートカットキーを設定することを前提に、「Windows Terminal」と「Mac Terminal」で使用できるショートカットキー表記を付録に掲載していたが、zshの場合はこちらの表記も変わることになる。今回は、この辺りをまとめた表を稿末に付録として掲載しておくので、いろいろ試してみたいという方は参考にしていただきたい。

シェルのショートカット設定はときに悩ましい

bashのショートカットキーを設定する話で何度が取り上げたが、インタラクティブシェルのショートカットキー設定はときにユーザーが思っている通りに進まないことがある。原因は複数のレイヤで存在している。いくつかピックアップすると、次のような感じだ。

  • OSレベルで使いたいキーやキーの組み合わせが存在していない
  • インタラクティブシェルにキーが到達するためにターミナルアプリケーションが該当するキーを奪っている
  • インタラクティブシェルに渡る前にターミナルの動作として該当するキーを奪っている
  • ターミナルアプリケーション環境において該当するショートカットキーの書き方が違う


使いたいショートカットキーが使えない場合、なぜ使えないのか上から下まで調べないといけないので、場合によってはすごく時間がかかるし、最終的にその環境だとどうやっても使えないことがわかることもある。

調査にあまりに時間がかかるようだと、いくらショートカットキーが便利だと言っても……、という気になる。しかし、その結果が将来に渡って入力の手間を省いてくれるなら、少し本腰を入れて調べてショートカットキーを設定しておいてもよいのではないだろうか。

本連載では、これまでに紹介してきたbashのショートカットキーと同じような状態になるようにzshのほうも設定していこう。LinuxでもMacでも同じショートカットキーが使えるようにしておくと便利だ。しばらくは、zshの設定を追っていこう。

付録 Windows Terminal キーとキー表記

キー キー表記
「ESC」 ^[
「ESC」「ESC」 ^[^[
「Home」 ^[[H
「Insert」 ^[[2~
「Delete」 ^[[3~
「End」 ^[[F
「Page Up」 ^[[5~
「Page Down」 ^[[6~
「F1」 ^[OP
「F2」 ^[OQ
「F3」 ^[OR
「F4」 ^[OS
「F5」 ^[O15~
「F6」 ^[O17~
「F7」 ^[O18~
「F8」 ^[O19~
「F9」 ^[O20~
「F10」 ^[O21~
「Alt」+「Home」 ^[[1;3H
「Alt」+「Insert」 ^[[2;3~
「Alt」+「Delete」 ^[[3;3~
「Alt」+「End」 ^[[1;3F
「Alt」+「Page Up」 ^[[5;3~
「Alt」+「Page Down」 ^[[6;3~
「Ctrl」+「Home」 ^[[1;5H
「Ctrl」+「Insert」 ^[[2;5~
「Ctrl」+「Delete」 ^[[3;5~
「Ctrl」+「End」 ^[[1;5F
「Ctrl」+「Page Up」 ^[[5;5~
「Ctrl」+「Page Down」 ^[[6;5~
「↑」 ^[[A
「↓」 ^[[B
「→」 ^[[C
「←」 ^[[D
「Alt」+「↑」 ^[[1;3A
「Alt」+「↓」 ^[[1;3B
「Alt」+「→」 ^[[1;3C
「Alt」+「←」 ^[[1;3D
「Ctrl」+「↑」 ^[[1;5A
「Ctrl」+「↓」 ^[[1;5B
「Ctrl」+「→」 ^[[1;5C
「Ctrl」+「←」 ^[[1;5D
貼り付け開始 ^[[200~
クエリステータスレポート ^[[5n
クエリステータスレポート(応答) ^[[0n
「Backspace」 ^?
「Ctrl」+「Backspace」 ^H
「Tab」 ^I
「Enter」 ^M

付録 Mac Terminal キーとキー表記

キー キー表記
「ESC」 ^[
「ESC」「ESC」 ^[^[
「Home」 なし
「Insert」 なし
「Delete」 ^[[3~
「End」 なし
「Page Up」 なし
「Page Down」 なし
「F1」 ^[OP
「F2」 ^[OQ
「F3」 ^[OR
「F4」 ^[OS
「F5」 ^[O15~
「F6」 ^[O17~
「F7」 ^[O18~
「F8」 ^[O19~
「F9」 ^[O20~
「F10」 なし
「F11」 ^[O23~
「F12」 ^[O24~
「Alt」+「Home」 なし
「Alt」+「Insert」 なし
「Alt」+「Delete」 なし
「Alt」+「End」 なし
「Alt」+「Page Up」 なし
「Alt」+「Page Down」 なし
「Ctrl」+「Home」 なし
「Ctrl」+「Insert」 なし
「Ctrl」+「Delete」 ^[[3;5~
「Ctrl」+「End」 なし
「Ctrl」+「Page Up」 なし
「Ctrl」+「Page Down」 なし
「↑」 ^[[A
「↓」 ^[[B
「→」 ^[[C
「←」 ^[[D
「Alt」+「↑」 なし
「Alt」+「↓」 なし
「Alt」+「→」 なし
「Alt」+「←」 なし
「Ctrl」+「↑」 ^[[A
「Ctrl」+「↓」 ^[[B
「Ctrl」+「→」 ^[[1;5C
「Ctrl」+「←」 ^[[1;5D
貼り付け開始 ^[[200~
クエリステータスレポート ^[[5n
クエリステータスレポート(応答) ^[[0n
「Backspace」 ^H
「Ctrl」+「Backspace」 ^H
「Tab」 ^I
「Enter」 ^M

付録 zsh bindkey 出力キー対応表

キー表記 キー zshzle標準ウィジェット
^[a 「ESC」「a」 accept-and-hold
^[A 「ESC」「A」 accept-and-hold
^J 「Ctrl」+「J」 accept-line
^M 「Ctrl」+「M」 accept-line
^O 「Ctrl」+「O」 accept-line-and-down-history
^[[D 「←」 backward-char
^[OD 「ESC」「O」「D」 backward-char
^B 「Ctrl」+「B」 backward-char
^? 「Backspace」 backward-delete-char
^H 「Ctrl」+「H」 backward-delete-char
^[^? 「ESC」「Backspace」 backward-kill-word
^[^H 「ESC」「Ctrl」+「H」 backward-kill-word
^W 「Ctrl」+「W」 backward-kill-word
^[b 「ESC」「b」 backward-word
^[B 「ESC」「B」 backward-word
^[< 「ESC」「<」 beginning-of-buffer-or-history
^A 「Ctrl」+「A」 beginning-of-line
^[[200~ 貼り付け開始 bracketed-paste
^[C 「ESC」「C」 capitalize-word
^[^L 「ESC」「Ctrl」+「L」 clear-screen
^L 「Ctrl」+「L」 clear-screen
^[^_ 「ESC」「Ctrl」+「_」 copy-prev-word
^[w 「ESC」「w」 copy-region-as-kill
^[W 「ESC」「W」 copy-region-as-kill
^D 「Ctrl」+「D」 delete-char-or-list
^[0 「ESC」「0」 digit-argument
^[1 「ESC」「1」 digit-argument
^[2 「ESC」「2」 digit-argument
^[3 「ESC」「3」 digit-argument
^[4 「ESC」「4」 digit-argument
^[5 「ESC」「5」 digit-argument
^[6 「ESC」「6」 digit-argument
^[7 「ESC」「7」 digit-argument
^[8 「ESC」「8」 digit-argument
^[9 「ESC」「9」 digit-argument
^[l 「ESC」「l」 down-case-word
^[L 「ESC」「L」 down-case-word
^[[B 「↓」 down-line-or-history
^[OB 「ESC」「O」「B」 down-line-or-history
^N 「Ctrl」+「N」 down-line-or-history
^[> 「ESC」「>」 end-of-buffer-or-history
^E 「Ctrl」+「E」 end-of-line
^X^X 「Ctrl」+「X」「Ctrl」+「X」 exchange-point-and-mark
^[z 「ESC」「z」 execute-last-named-cmd
^[x 「ESC」「x」 execute-named-cmd
^[ 「ESC」「 」 expand-history
^[! 「ESC」「!」 expand-history
^X* 「Ctrl」+「X」「*」 expand-word
^[[C 「→」 forward-char
^[OC 「ESC」「O」「C」 forward-char
^F 「Ctrl」+「F」 forward-char
^[f 「ESC」「f」 forward-word
^[F 「ESC」「F」 forward-word
^[c 「ESC」「c」 fzf-cd-widget
^I 「Ctrl」+「I」 fzf-completion
^I 「Tab」 fzf-completion
^T 「Ctrl」+「T」 fzf-file-widget
^R 「Ctrl」+「R」 fzf-history-widget
^[g 「ESC」「g」 get-line
^[G 「ESC」「G」 get-line
^Xr 「Ctrl」+「X」「r」 history-incremental-search-backward
^S 「Ctrl」+「S」 history-incremental-search-forward
^Xs 「Ctrl」+「X」「s」 history-incremental-search-forward
^[p 「ESC」「p」 history-search-backward
^[P 「ESC」「P」 history-search-backward
^[n 「ESC」「n」 history-search-forward
^[N 「ESC」「N」 history-search-forward
^X^N 「Ctrl」+「X」「Ctrl」+「N」 infer-next-history
^[_ 「ESC」「_」 insert-last-word
^[. 「ESC」「.」 insert-last-word
^X^K 「Ctrl」+「X」「Ctrl」+「K」 kill-buffer
^K 「Ctrl」+「K」 kill-line
^U 「Ctrl」+「U」 kill-whole-line
^[d 「ESC」「d」 kill-word
^[D 「ESC」「D」 kill-word
^[^D 「ESC」「Ctrl」+「D」 list-choices
^Xg 「Ctrl」+「X」「g」 list-expand
^XG 「Ctrl」+「X」「G」 list-expand
^[- 「ESC」「-」 neg-argument
^X^O 「Ctrl」+「X」「Ctrl」+「O」 overwrite-mode
^[q 「ESC」「q」 push-line
^[Q 「ESC」「Q」 push-line
^Q 「Ctrl」+「Q」 push-line
^[‘ 「ESC」「’」 quote-line
^[" 「ESC」「”」 quote-region
^V 「Ctrl」+「V」 quoted-insert
^[h 「ESC」「h」 run-help
^[H 「ESC」「H」 run-help
“-“~ 「 」から「~」までの文字 self-insert
\M-^@”-“\M-^? 「Alt」+「Ctrl」+「@」から「Alt」+「Ctrl」+「Backspace」までの入力 self-insert
^[^I 「ESC」「Tab」 self-insert-unmeta
^[^J 「ESC」「Ctrl」+「J」 self-insert-unmeta
^[^M 「ESC」「Ctrl」+「M」 self-insert-unmeta
^[^G 「ESC」「Ctrl」+「G」 send-break
^G 「Ctrl」+「G」 send-break
^@ 「Ctrl」+「@」 set-mark-command
^[\$ 「ESC」「$」 spell-word
^[s 「ESC」「s」 spell-word
^[S 「ESC」「S」 spell-word
^[t 「ESC」「t」 transpose-words
^[T 「ESC」「T」 transpose-words
^_ 「Ctrl」+「_」 undo
^X^U 「Ctrl」+「X」「Ctrl」+「U」 undo
^Xu 「Ctrl」+「X」「u」 undo
^[u 「ESC」「u」 up-case-word
^[U 「ESC」「U」 up-case-word
^[[A 「↑」 up-line-or-history
^[OA 「ESC」「O」「A」 up-line-or-history
^P 「Ctrl」+「P」 up-line-or-history
^X^V 「Ctrl」+「X」「Ctrl」+「V」 vi-cmd-mode
^X^F 「Ctrl」+「X」「Ctrl」+「F」 vi-find-next-char
^[| 「ESC」「|」 vi-goto-column
^X^J 「Ctrl」+「X」「Ctrl」+「J」 vi-join
^X^B 「Ctrl」+「X」「Ctrl」+「B」 vi-match-bracket
^X= 「Ctrl」+「X」「=」 what-cursor-position
^[? 「ESC」「?」 which-command
^Y 「Ctrl」+「Y」 yank
^[y 「ESC」「y」 yank-pop