zshで究極のオペレーションを

第3回 zsh使いこなしポイント即効編

この記事を読むのに必要な時間:およそ 7 分

キーカスタマイズ

シェルを手に馴染ませるために比較的簡単にできる設定の1つがキーカスタマイズである。そのための要点を示しておこう。

bindkeyコマンドとキーマップ

zshのキー割り当てはbindkeyコマンドで行なう。zshには複数のキーマップがあり,それぞれ全く違う操作体系のキー割り当てセットが格納されている。主なものにemacsキーマップ,viins(viの挿入モード)キーマップ,vicmd(viのコマンドモード)キーマップがある。emacs風の操作感を好む場合は,以下のようにemacsキーマップを選択する。

% bindkey -e

vi風の操作感を好む場合は,以下のようにviinsキーマップを選択する。

% bindkey -v

実はzshではさらに違うユーザ独自の新たなキーマップを作ることもできるし,キーに割り当てる機能(ウィジェット)をシェル関数で独自に作ることもできる。たとえば,以下のようにするとC-fでのカーソル移動が「3歩進んで2歩下がる」になる。

# 新しいウィジェットとなる関数 365march-forward() を定義
function 365march-forward () {
  : ${_365march:-0}
  if ((_365march++ % 4)) then
    zle forward-char
  else
    zle backward-char -n 2
  fi
}
# この関数をウィジェット化
zle -N 365march-forward
# emacsキーマップを見本に新しいキーマップ365marchを作る
bindkey -N 365march emacs
# 365marchキーマップの C-f に 365march-forward を割り当てる
bindkey -M 365march '^f' 365march-forward
# 使用するキーマップを 365march に変える
bindkey -A 365march main

この状態でコマンドラインに何文字か打って行頭に戻りC-a⁠,その後C-fを連打してみよう。もちろんまったく使い道がないのでキーマップをemacsに戻しておこう。

% bindkey -e

かくも過激な機能拡張ができるzshだが,ウィジェットの説明は別の機会に譲り,ここではもっとも利用者が多いと思われるemacs風キー割り当てでの簡単なカスタマイズ例をいくつか示そう。

ヒストリ呼出しのカスタマイズ

シェルを使い始めの頃は,(またはC-pキーを連打して前に打ったコマンドがどんどん戻ってくるというだけでずいぶんありがたく感じるものだが,より効率的にコマンド入力するなら,呼び戻そうとしている過去のコマンドラインに一発で辿り着けた方がよい。

そのためには検索機能つきで古いコマンドラインに戻る機能を用いればよい。その検索方法には大別して2つがある。

  • 行頭マッチの検索
  • インクリメンタル検索(EmacsでいうC-sC-r

zshのemacsキーマップのデフォルトではC-pC-nに検索なしの機能が割り当てられているが,これを検索つきに変えてしまっても問題なく,そのほうが狙ったコマンドラインの呼出しが楽になる。

bindkey '^p' history-beginning-search-backward
bindkey '^n' history-beginning-search-forward

これは,コマンドラインに途中入力した文字があれば,それと同じ文字列で始まるコマンドラインに移動する。tcshにある同種の先頭文字検索機能と違い,これらはカーソルの桁位置が保存されたままマッチするものに移動する。例を示す。

grep foo /usr/local/apache/logs/access_log
tail -f /usr/local/apache/logs/error_log
gimp &

コマンド入力履歴が上記のような場合に,次のコマンドラインでgrep まで入力してhistory-beginning-search-backwardを呼び出すとカーソル位置は以下のようになる。

% grepC-p        (C-pには history-beginning-search-backward が割り当てられている)
       ↓
% grep foo /usr/local/apache/logs/access_log
      ↑カーソル位置(pの次)

カーソルが行末に来る挙動に慣れていると最初はぎょっとするが,たとえば上記の例だとgrepの検索パターンを変えて何度も試したりするにはカーソル位置がその場の方が好都合だ。状況によるので一概にどちらが有利不利とは言えない。ただ,行末に移動するのはC-eですぐ行けるものの,中途位置にはすぐ行けないので,あらかじめカーソルが位置するのは中途位置の方がよいことの方が多いと経験上感ずる。

どうしても行末にカーソルが来た方がよい場合は別の機能を割り当てるとよい。

autoload -U up-line-or-beginning-search down-line-or-beginning-search
zle -N up-line-or-beginning-search
zle -N down-line-or-beginning-search
bindkey '^p' up-line-or-beginning-search
bindkey '^n' down-line-or-beginning-search

エディタ(vi)とコマンドラインの往復

tcshの行エディタにある便利な機能にrun-fg-editorというものがある。これは,入力途中のコマンドラインを保存したままsuspendしているエディタに戻る(フォアグラウンドにする)機能である。この機能はtcshのデフォルトでM-C-zに割り当てられているが,これをC-zに割り当てると,以下のようにC-z ーだけでviとコマンドラインを往復でき非常に便利である。

viC-z


C-z
コマンドライン

これと同じことをzshで行なうには,コマンドラインスタックESC-qを利用するキーの流れをbindkey -sで登録する。C-zに割り当てる例を示す。

setopt hist_ignore_space
bindkey -s '^z' '^[q %vi^m'

これは,C-zを押したときに,ESC-qを押してから" %vi"を挿入し,C-mをタイプした」ように振る舞う。%vi はシェルの管理下にあるジョブのうち,viという文字列で始まるジョブをフォアグラウンドにすることを意味し,その前にあるスペース1つはこれをヒストリに登録しないことを意味する(シェルオプションhist_ignore_space有効時⁠⁠。

ちなみに筆者自身は「vi決め打ち」ではなく,⁠環境変数EDITORに登録されているエディタ」で処理したいので以下のようにしている。

export EDITOR=vim
alias vi='$EDITOR'
bindkey -s '^z' '^[q %\\$EDITOR^m'