1.初めに
Macで標準シェルがbash
からzsh
に変わったので、zsh
の補完について勉強してみました。bash
でもプログラム可能な補完ができますが、zsh
はそれよりも高水準の機能の補完を標準で盛り込んでいます。主にbashではできないような補完機能について述べていきます。
・参考文献
zshの本
2.zshの補完システム
zshには大別してcompsys、compctlという2つの補完システムが存在する。バージョン3.1.6より導入された新補完システムがcompsys、それよりも前から存在するcompctlという旧補完システムである。
新補完システムであるcompsysについて今回は見ていく。compsysで用意されている全ての補完機能を有効にするには以下のコマンドを実行する。デフォルトではcompsysは有効ではないので注意。よく使うのでこのコマンドは~/.zshrc
などに書き込んでおくのも良い。
autoload -U compinit
compinit
3.補完のキーについて
既にシェルを使っている人は知っているとは思うが、補完をするにはtab
を押す。このキーはCtrl-i
でも同じなので、どちらの入力でもOK。
また、補完候補を表示するのは行末でCtrl-d
。
なお文字上にカーソルがあると、Ctrl-d
は1文字削除を表すので注意。また補完候補が複数ある時にtab
を連打しても補完候補が表示される。
4.補完機能の概観
tab
で補完できるのは、コマンド、コマンドのオプションやサブコマンド、ファイル名、変数、ユーザ名、ホスト名、プロセス、ジョブなど非常に幅広い。これらはcsh
やbash
でも同じように補完できるのが大半だが、zsh
に特有のものを少し紹介する。
4.1 ファイル名補完
compsysのファイル名補完では、部分マッチによる補完が有効。予め決められた区切り記号(デフォルトでは/
)の直前に*を自動で補って補完する。例えば/usr/local/bin
に行きたい時に/u/lo/b
と打ってtab
を押すだけで良い。
↓ tab
4.2 変数補完
行頭では環境変数の代入文も記入できる(その環境変数が一時的に代入された状態でそのコマンドを実行できる)という機能があるため、行頭での変数補完もある。
↓ tab
4.3 プロセス補完
kill
コマンドの引数位置でtab
を押すと、プロセス一覧が表示される。
↓ tab
また、コマンド名をPID(プロセスID)に自動変換もしてくれる。
↓ tab
4.4 展開機能
tab
には補完機能だけでなく、展開機能もついているので注意が必要である。
具体的には
- ファイル名展開
- ヒストリ展開
- 変数展開
- ブレース展開
などがある。これらはコマンドの実行時に内部的に変換処理が行われるものだが、コマンドラインで先にtab
を打つことで前もって変換させることもできる。補完機能ではなく本筋からズレるため詳しく扱わないが、代表的なものだけ少し紹介する。
4.4.1 ファイル名展開
*
は、任意の文字列に対応して、ファイル名展開を行う。
4.4.2 ヒストリ展開
ヒストリ機能には!!
というコマンドがあり、これは一つ前に実行したコマンドを表す。
上の例ではls --color
を再び実行している。この!!
を実行する前にtab
を押すことで、先にls --color
を表示させることができる。
↓ tab
同じtab
キーを使用するので混乱しがちだが、違う機能なので注意が必要である。
それでは補完の話に戻る。
5.メニュー補完
zsh
で便利な機能として、メニュー補完がある。これは補完候補がたくさんある時にtab
を連打すると順番にその候補からコマンドラインに挿入してくれる。以下に具体例を載せる。
ls D
と入力した状態でtab
を押すと候補一覧が表示
↓ tab
で、一つ目のDesktopが挿入
↓ 再びtab
で、二つ目のDocumentsが挿入
↓ 再びtab
で、三つ目のDownloadsが挿入
↓ 再びtab
で、一つ目のDesktopが挿入
以下サイクルになる。これもbash
には標準で入っていない機能である。
6.補完スタイル
ここからはより細かく補完を制御する話になる。少し込み入っているので、初見の方は特に自分で実際にやってみることをお勧めする。
compsysではシェルオプションによりもきめ細かい設定ができるスタイルによって挙動を制御する。
スタイルとは、compsysが補完を行う時に「どのようなことをどう行うか」を指定するためのものである。これに与える値として、真偽値だけでなく文字列や条件も与えることができる。また、シェルオプションが補完を行う全ての局面で有効になるのに対して、スタイルによる指定はどのような状況で補完機能を呼び出したかを表すコンテクストに応じて設定値を変えることができる。
あるパターンPattern
にマッチするコンテクストで、ある特定のスタイルStyle
の値をValue
に設定するにはzstyle
コマンドを用いる。構文は以下。
zstyle Pattern Style Value
上記だけだと理解しづらいため、これから実際の例を見ていく。
・デフォルトではメニュー補完をするが、rm
の引数の時にはメニュー補完をしない。
zstyle ':completion:*' menu true
zstyle ':completion:*:rm:*' menu false
・less
とcd
の引数入力時、小文字で打った文字列で補完した時に、小文字大文字両方のファイル名にマッチさせる。
zstyle ':completion:*:(cd|less):*' matcher 'm:{a-z}={A-Z}'
zstyle
の第一引数に与えているのがコンテクストで、実際の値は6つのフィールドをコロンで区切って並べたものになる。
completion:Func:Completer:Cmd-or-Context:Arg:Tag
-
completion
は、補完システムで使うことを意味する固定文字列 -
Func
は、補完システムではなく名前付きウィジェットから呼ばれた場合の関数名(多くの場合空) -
Completer
は、コンプリーター(補完ならcomplete、展開ならexpandなど) -
Cmd-or-Context
は、保管中のコマンド・サブコマンド・その他文脈を表すシンボル -
Arg
は、どの位置の引数を補完しているかを表すシンボル -
Tag
は、どういう種類のものを補完しているかを表すシンボル
rm
のメニュー補完の例では、completion:*:rm:*
のように4つしか指定していないが、これは*
が複数のフィールドにまたがっているだけである。ちゃんと書くならcompletion:*:*:rm:*:*
となる。
初めのうちは各フィールドの意味を詳細に知る必要はなく、とりあえずcompletion:*
あるいはcompletion:*:コマンド名:*
で十分である。本記事ではFunc
やArg
、Tag
については詳しく扱わない。
6.1 代表的なスタイル
補完スタイルの変更は、「どんな状況で」「何を」「どのように」変えるかを組み合わせて指定する。先ほどの例であったようなmenu
スタイルは「メニュー補完の挙動」、matcher
スタイルは「マッチしたとみなす文字集合列」を制御するスタイルである。
スタイルは非常にたくさんあり、バージョン5.0.7現在で111ものスタイルがある。
(バージョン5.9現在で170あることを確認)
今回は適用用途の広い、代表的なスタイルについて示す。
6.1.1 補完提示方式の変更(menuスタイル)
menu
スタイルは、メニュー補完に加えてメニュー選択も設定できる。これは候補一覧をカーソルで移動して選べる方式である。メニュー補完を有効化するtrueに加えて、メニュー補完の形式をメニュー選択にするselect
も追加文字列として指定できる。
zstyle ':completion:*:setopt:*' menu true select
この状態でsetopt autoと入力してからtab
を打つと、メニュー選択になり、矢印キーが使えるようになる。
6.1.2 一覧の表示属性設定(list-colorスタイル)
list-color
スタイルを用いれば、候補一覧を色や文字装飾付きで区別して表示できる。
例えば「ディレクトリは下線付きで、実行ファイルは黄色で、拡張子が.cのファイルは紫で表示」なら以下。
zstyle ':completion:*:default' list-colors di=4 ex=33 '=*.c=35'
設定値は「種別=表示属性」の形式を列挙する。種別には以下のようなものがある。
種別 | 意味 |
---|---|
fi | 通常ファイル |
di | ディレクトリ |
ex | 実行ファイル |
ln | リンクファイル |
=パターン | 「パターン」にマッチする候補 |
表示属性(XYという数字) | Y=0 | Y=1 | Y=2 | Y=3 | Y=4 | Y=5 | Y=6 | Y=7 |
---|---|---|---|---|---|---|---|---|
Xが空で属性設定 | 標準 | 太字 | 下線 | 点滅 | 反転 | |||
X=1で属性解除 | 太字 | 下線 | 点滅 | 反転 | ||||
X=3で文字設定 | 黒 | 赤 | 緑 | 黄 | 青 | 紫 | 水色 | 白 |
X=4で背景設定 | 黒 | 赤 | 緑 | 黄 | 青 | 紫 | 水色 | 白 |
list-colors
にスタイルに空文字列を設定すると、GNU lsと同様の色分けになる。
6.1.3 マッチ仕様の調整(matcherスタイル)
補完時にはマッチするものを補う。この「マッチする」という定義自体を変えることができる。
例えばfooまで打って補完すると、fooという3文字が先頭から完全に一致するものだけが補完候補として残るが、これを「大文字と小文字を区別しないで一致とする」というように変更できる。以下これをマッチ仕様という。
マッチ仕様の変更は、全域的な設定はmatcher-list
スタイルで行い、ある特定のタグだけに適用させたい時にはmatcher
スタイルで行う。標準的な補完動作をmatcher-listに定義しておき、特定のコマンドの補完時だけより柔軟な変更したい、というような時には、そのコマンド名を含むコンテクストに対するmatcher
スタイルの値を定義する。matcher
スタイルに設定できる値は、matcher-list
スタイルに適用できる値と同じである。
入力した単語の全ての文字を別のものに変えてマッチ試行させるには、
m:Lpattern=Tpattern
M:Lpattern=Tpattern
という書式を使う。これはコマンドライン上のLpattern
にマッチする文字列をTpattern
に置き換えたものでマッチングを行うことを指示する。ファイル名のように大文字と小文字が違うとエラーになるものはm
を、シェルオプションのように大文字と小文字が同じように解釈されるものの補完ではM
を使う。
例えば
zstyle ':completion:*' matcher-list 'm:to=2'
のように定義すれば元の単語のtoを2に置き換えてくれるので、以下のようにpdftoだけでなくpdf2も補完候補に含められる。
6.1.4 ホスト名・ユーザ名の候補(hostsスタイル、usersスタイル)
補完対象の単語の種類を表すのがタグであるが、ssh
やping
はどれも引数にホスト名を要求するように、別のコマンドでも同じタグを要求することがある。このような時は、このタグそのものの候補をまとめて変更することで、そのタグを要求するコマンド全ての補完候補を変えることもできる。
ホスト名の候補はhosts
スタイル、ユーザ名の候補はusers
スタイル、ユーザ名とホスト名を組み合わせた候補はusers-hosts
スタイルで設定する。例えば以下。
zstyle ':completion:*:ping:*' hosts aa.example.ne.jp bb.example.com cc.example.ac.jp
この設定では、pingの際のホスト名の補完候補が上記3つのものになる。
zstyle ':completion:*:ssh:*' users-hosts user1@{host1,host2} users2@{host3,host4}
この設定では、sshの際にユーザ名にuser1を入れた時はhost1かhost2だけが、user2を入れた時はhost3かhost4だけが補完候補となる。
6.1.5 ソート(sortスタイル、file-sortスタイル)
候補一覧は通常文字コード順にソートさせるが、候補を好きな順番に登録してその順番に出して欲しい時もある。これにはファイル名以外のソートにはsort
スタイルを用いる。
zstyle ':completion:*:ping:*' sort false
ファイル名のソートにはfile-sort
スタイルで設定する。例えばlarge、small、very_large、very_smallという名前のファイルがある時、通常は文字コード順に候補が表示される。
これをファイルサイズ順に表示するには以下。
zstyle ':completion:*' file-sort size
これで候補一覧の順番がサイズ順になる。
設定値には以下のいずれかを含む文字列とする。文字列にreverseを追加すると、逆順でソートされる。
設定値 | ソートの基準 |
---|---|
size | ファイルサイズ |
links | リンクカウント |
modification, date, time | ファイル修正時刻 |
access | 最終アクセス時刻 |
inode, change | inode修正時刻 |
6.2 コンプリータ
これまでに述べた補完機能は、_complete
というコンプリータによるもので、先頭部分を入力してそれにマッチするものを補うのが主な役割である。それ以外にも、綴り間違いを修正したり、シェルの展開機能を施すコンプリータがある。
コマンドラインで補完が要求された時に利用されるコンプリータは複数登録できる。それはcompleter
スタイルで指定する。
zstyle ':completion:*' completer Completer1 Completer2 ...
このように設定すると、先頭に書かれたものから順次呼び出され、どれかのコンプリータでマッチが見つかると、以後のものは呼ばれない。
6.2.1 近似補完(_approximate
)
_approximate
コンプリータは近似マッチと同じ間違い修正をした上で補完する。このコンプリータを使う場合は、通常以下のように_complete
コンプリータの後で稼働するように設定する。
zstyle ':completion:*' completer _complete _approximate
これにより、_complete
による通常補完でマッチするものが探せなかった時に限り近似補完をする。この近似マッチの精度を制御するスタイルはmax-errors
スタイルで、間違いの許容数を指定する。デフォルトでは以下のように許容数は2である。
zstyle ':completion:*:approximate' max-errors 2 NUMERIC
ここでいう間違いとは「文字違い(hogeがhage)」「順番違い(emacsがemasc)」「文字抜け(magickがmagic)」「文字超過(magicがmagick)」のことである。
この状態で試しにzshをzhsと打ち間違えてCtrl-d
を押すと以下のようになる。
6.2.2 綴り修正(_correct
)
_approximate
が既に入力した部分文字列を修正してからさらに補完するのに対し、入力を終えたとみなせる単語の綴り修正のみを行うのが_correct
コンプリータである。
zstyle ':completion:*' completer _complete _correct
6.2.3 単語途中の補完(_prefix
)
例えば/usr/share/manを入力しようとし、/usr/maまで打ってからshareディレクトリに気付いて入力し直すとする。
この時以下のような状況になるが、この位置で補完してもパス区切りをまたいだマッチングは起きないので、shaの部分がshareに補完されることはない。
この場合、カーソル以降を無視してカーソル以前の部分だけで補完するコンプリータ_prefix
が有用である。_prefix
は他のコンプリータと違い、それ自身が独自の補完方式を持つのではなく、単語中のカーソル以降の文字を除去した単語に対して、その時点で呼び出されるべき全てのコンプリータを呼ぶ。
zstyle ':completion:*' completer _complete _approximate _prefix
とすると、最初に_complete
と_approximate
が呼ばれ、それでも補完されない時に_prefixが呼ばれて、カーソル以後の文字列を無視した状態でまた_complete
と_approximate
が呼ばれる。
_prefix
コンプリータが発動する時に呼ばれるコンプリータを本来のものとは違うものにもできる。その場合は例えば
zstyle ':completion::prefix:*' completer _complete
のようにコンプリータフィールドにprefixを入れたものでcompleter
スタイルの指定を行う。
7.終わりに
zshの補完には非常にたくさんの種類があります。特にスタイルなんかはたくさんあるので、man zshcompsys
なんかで確認しましょう。