今回はzshの誇る機能の花形とも言える補完機能について紹介しよう。zshの補完は強大で、例示した設定の意味を略さず書こうとするとそれだけで本 になってしまう(約150ページ分)ので、細かい意味は読者の推測にまかせて、少し変えて便利にカスタマイズする場合のヒントを交えながら解説を進めたい。
補完の有効化
初期化ファイル、あるいはコマンドラインで、以下を入力することでzshのすぐれた補完機能が有効化される。
autoload -U compinit && compinit
補完に関するキー割り当てはいくつもあるが、最低限うまく利用するために以下の2つのキーバインドをまず覚えておけばよいだろう。
Tab (C-i ) - expand-or-complete
補完の実行。
ESC C-d (または行末のみ C-d ) - list-choices
(delete-char-or-list
)
マッチする候補の一覧表示。
ちなみに、正確には補完システムの機能ではないが、( 標準では)ファイル名のみに働く以下のキーも覚えておくと有用である。
C-x* - expand-word
カーソル位置に含まれる単語をシェルの展開規則によってその場で展開。
C-xg - list-expand
カーソル位置に含まれる単語がどのように展開されるかを一覧表示。
Tab による補完とESC C-d による候補表示を使いながら標準装備されているきめ細やかな補完を確認してみよう。ただし、標準でONになっているシェルオプションautolist
によってTab 補完時、同時に候補一覧表示もなされる。普段OFFにしている場合で候補一覧を明示的に得る場合はESC C-d を利用することになる。
以下に、代表的な補完システムの挙動を示す。なお実行例はサンプル zshrc
をロードした状態を前提としている部分がある。
1.ファイル名補完
他のシェルにもある最も基本的なファイル名補完は、基本的にはファイル名の先頭部分だけの入力を完全なものに補う機能だが、zshの場合は入力をさらに節約できる機能が備わっている。
% cd /us Tab
% cd /usr/ (/us で始まるファイル名に)
% cd /u/l/a/co Tab
% cd /usr/local/apache/conf/ (/ の前に * を補ったパターンで補完)
このように、スラッシュを区切りとして直前に*
があると見なして補完することで、一意に定まるパス名を極力短く指定することができる。この機能はEmacsのファイル名入力にも実装されている(~/.emacs
などで (partial-completion-mode t)
している場合)ので既になじんでいる人も多かろう。
tcshで `set complete=enhance
' している場合も同様の部分補完ができる。tcshではピリオド、ハイフン、アンダースコアを区切りとして同様の補完をしたり、大文字と小文字を同一視して補完したりするが、zshでこれを行なうには以下のようにすればよい。
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z} r:|[-_.]=**'
これは、「 a-zをそれぞれ対応するA-Zに置き換えて、A-Zもそれぞれ対応するa-zに置き換えて補完してみるのと同時に、右側にハイフンかアンダースコアかピリオドが来る場所には *
を補ったかのように補完してみる」ことを指示するもので、これにより以下のような補完挙動が得られる。
% ls -F
extra/ httpd.conf magic mime.types original/
% less m.t Tab
% less mime.types
タイプ数削減の大きな味方だ。ところが、やみくもに部分補完を行なう文字を増やすと逆に不便になる場合もある。例を示そう。
% ls
highperformance-std.conf magic
highperformance.conf mime.types
httpd-std.conf ssl-std.conf
httpd.conf ssl.conf
このようなファイルがある場合にhttpd.conf
を編集しようと以下のように補完すると期待どおりにいかない。
% vi httpd. Tab
% vi httpd-std.conf
これは、`httpd.
' までタイプすればファイル名が一意に定まると思ってそこまでしっかり打ったのに、Tab を押したら想定外の httpd-std.conf
が出てがっかり、という例である。zshでは「一意に決まるファイルがあるかもしれないから、まずそのまま補完せよ」と設定しておくこともできる。これには先のzstyle
例を以下のように変更する。
zstyle ':completion:*' matcher-list '' 'm:{a-zA-Z}={A-Za-z} r:|[-_.]=**'
中央付近に足した ''
がそれで、マッチング規則の変更をまずなし(''
)でやってみて、それでマッチするものがなければ次の引数の 'm:{a-zA-Z}={A-Za-z} r:|[-_.]=**'
という規則適用でやれ、ということを意味している。
もうひとつ例を欲張っておこう。「 大文字小文字を同一視」をONにしたときも、検索文字列としてわざわざ大文字をあらかじめ入れた場合は大文字にだけマッチして欲しい。その場合以下のよう設定が有用となる(大文字小文字に関する部分のみ記述) 。
zstyle ':completion:*' matcher-list '' 'm:{a-z}={A-Z}' '+m:{A-Z}={a-z}'
これは、以下のようなルール記述を意味する。
まず入力された文字そのままで補完してみて
それでマッチするものがなければ、小文字を大文字に変えつつ補完してみて
それでもマッチするものがなければ、大文字を小文字に変えるルールを追加(`+
')して補完してみよ
以上文字の種別を変えて補完を試みる設定を示したが、これはファイル名補完に限らずその他の補完すべてでも有効化させられる。
2.変数補完
コマンドラインでシェル変数や環境変数を入力しようとしている場所では変数名を補完する。通常、コマンドライン先頭はコマンド名か、変数代入時の変数名が来るが、大文字の場合はマッチするものが変数に限られることが多い。
% MA Tab
Completing parameter
MACHTYPE MAILCHECK MAILDIR MAILPATH MANPATH
% MAN Tab
% MANPATH=
また、変数展開は$VARIABLE
という形式だけでなく、たとえば ${HOME}
あるいは$HOME:h
のような形もよく利用する。zshではこれらも目の前に展開することなく正しく補完できる。
(ホームディレクトリの親ディレクトリにアクセスする例)
% ls ${HO Tab
Completing parameter
HOME HOST
% ls ${HOM Tab
% ls ${HOME}/
($HOME値がパス名なので自動的に / が補われる)
(続けて : を入力する)
% ls ${HOME:
(}/ が自動的に消えるので h}/ を入力)
% ls ${HOME:h}/ Tab
Completing files
....
($HOME/../ にあるファイル(ディレクトリ)一覧が表示される)
3.ユーザ名・ホスト名補完
SSHのように引数にユーザ名やホスト名を必要とする引数位置では、それにふさわしい補完が行なわれる。
% ssh y Tab
Completing remote host name
yankee yourpc.example.com
Completing login name
yas yukita yuuji
sshコマンドでは、以下の書式が許される。
ssh remotehost
ssh username @remotehost
そのため `ssh y
' とだけ入力した y
はホスト名、ユーザ名両方の可能性があり、補完候補も両方が提示される。ホスト名の候補は標準でgetent hostsコマンドの出力や~/.ssh/known_hosts
ファイルから自動的に取得され、ユーザ名の候補はシステムにホームディレクトリを持つユーザ一覧から取られるため、個人が利用するときの候補としては多すぎることが多い。
候補とするユーザ名、ホスト名を独自のものに設定するには、たとえば以下のようにする。
zstyle ':completion:*' users-hosts \
user1@{host1,host2} {user2,user3}@{host3,host4}
この記述は、ログイン先ホスト名としてhost1, host2, host3, host4を候補として設定し、そのうちhost1とhost2にログインするときのユーザ名をuser1に、host3とhost4にログインするときのユーザ名をuser2とuser3として設定している。
上記の設定で補完を行なうと以下のようになる。
% ssh Tab
Completing remote host name
host1 host2 host3 host4
Completing login name
user1 user2
% ssh u Tab
% ssh user
% ssh user1 Tab
% ssh user1@
% ssh user1@Tab
% ssh user1@host
% ssh user1@hostTab
Completing remote host name
host1 host2
なお、「 ユーザ@ホスト」の形式ではなくユーザ名だけ、あるいはホスト名だけが引数として認められるような場所は、それぞれ以下のようにusers
、hosts
スタイルを設定する。
(ユーザ名のみの場合の補完単語設定)
zstyle ':completion:*' users user1 user2 user3 user4 ...
(ホスト名のみの場合の補完単語設定)
zstyle ':completion:*' hosts host1 host2 host3 host4 ...
4.プロセス・ジョブ補完
kill
コマンドのように、引数位置にプロセスIDやジョブ記法を要求する位置で補完機能を呼ぶと、zshはその場で指定可能なプロセスを調べて候補として提示してくれる。
% jobs
[1] suspended sudo -H -s
[2] - suspended emacs -nw
[3] + suspended $EDITOR .zshrc
% ps
PID TTY STAT TIME COMMAND
356 ttyp0 Is+ 0:00.07 -zsh
1844 ttyp2 O+ 0:00.00 ps
25114 ttyp2 Ss 0:00.23 -zsh
26716 ttyp2 T 0:00.01 vim .zshrc
28066 ttyp2 T 0:00.52 emacs -nw (emcws)
(上記のようなプロセス起動状況と仮定)
% kill Tab
Completing process ID
356 ttyp0 Is+ 0:00.07 -zsh
25114 ttyp2 Ss+ 0:00.23 -zsh
26411 ttyp2 S+ 0:00.00 -zsh
26716 ttyp2 T 0:00.01 vim .zshrc
27519 ttyp2 O+ 0:00.00 ps
28066 ttyp2 T 0:00.52 emacs -nw (emcws)
(psを裏で起動してkillできるPIDが提示される
さらに % まで入れるとジョブが補完候補となる)
% kill % Tab
Completing job
%1 -- sudo -H -s
%2 -- emacs -nw
%3 -- $EDITOR .zshrc
このように事前にps
コマンドなどを打たずとも、シグナルを送れるプロセスの指定方法を知ることができる。
しかし、zshユーザとしてはこれでもまだ不満を感じなければならない。ps
の結果がたくさん出てきたりすると、どのPIDがどのプロセスに対応しているのか見分けるのがたいへんだし、kill
でPIDを指定するときに番号を打ち間違ったりする危険性もある。
以下のようにプロセス指定の場所ではメニュー選択モード
に移行するようzstyle
指定を行なうと、メニュー中のカーソルを移動させて確実にPIDを選ぶことができる。
zstyle ':completion:*:processes' menu yes select=2
コマンドラインでもこれを設定してから実際に補完してみよう。
% kill Tab
Completing process ID
356 ttyp0 Is+ 0:00.07 -zsh
1084 ttyp2 S+ 0:00.00 -zsh
9911 ttyp2 O+ 0:00.00 ps
25114 ttyp2 Ss+ 0:00.28 -zsh
26716 ttyp2 T 0:00.01 vim .zshrc
28066 ttyp2 T 0:00.52 emacs -nw (emcws)
(1行目が反転表示される。
さらにもう一度Tab をタイプすると)
% kill Tab
Completing process ID
356 ttyp0 Is+ 0:00.07 -zsh
1084 ttyp2 S+ 0:00.00 -zsh
9911 ttyp2 O+ 0:00.00 ps
25114 ttyp2 Ss+ 0:00.28 -zsh
26716 ttyp2 T 0:00.01 vim .zshrc
28066 ttyp2 T 0:00.52 emacs -nw (emcws)
(次の候補に進み2行目が反転表示される。
C-n、C-p でも下、上に移動できる。Returnで確定。
確定するとPIDの番号のみがコマンドラインに入る。)
このメニュー選択モードは、プロセス指定だけでなくファイル名やユーザ名など他の補完のときも使用できる。もし、PIDの選択だけでなくジョブ記法でもメニュー選択を有効化したい場合は以下のようにすればよい。
zstyle ':completion:*:(processes|jobs) ' menu yes select=2
指定した値の最後の select=2
は、補完対象となる語が2つ以上ある場合にのみメニュー選択モードを有効化するという意味である。もっとも、メニュー選択のほうが使いやすいという局面は限られるので、やみくもに設定するのは得策でない。
5.文脈追跡補完
これまで例示した典型的な補完語種別のほかにも、文脈にふさわしい候補を提示するような補完関数が標準で多数用意されている。それらのうちとくに効果的と思われるものをいくつかピックアップし、実例で示そう。
([1]./configure や make は、その場のファイルを実際に解析して
引数として適切な補完候補を設定)
% pwd
/home/yuuji/make/apache/apache22/httpd-2.2.13
(Apache2.2 のソースのディレクトリ)
% ./configure -- Tab
zsh: do you wish to see all 272 possibilities (273 lines)? y
Completing no arguments
Completing option
--bindir -- user executables (EPREFIX/bin)
--build -- configure for building on BUILD # (guessed)
--cache-file -- cache test results in FILE (disabled)
--config-cache -- alias for `--cache-file=config.cache'
--datadir -- read-only architecture-independent # data (DAT
--datarootdir -- read-only arch.-independent data root # (PREFI
:
:
(以下省略)
([2] 処理対象ファイルに応じて補完候補を決定 - tarの場合)
% tar jxpf h Tab
% tar jxpf httpd-2.2.13.tar.bz2 Tab
(補完候補取得にアーカイブ内部を調べるのに少し時間がかかる)
% tar jxpf httpd-2.2.13.tar.bz2 httpd-2.2.13/
(格納されているファイル名の共通プレフィクス(ディレクトリ)が出る
続けて Tab)
% tar jxpf httpd-2.2.13.tar.bz2 httpd-2.2.13/tab
Completing file from archive
.deps LICENSE acinclude.m4 httpd.spec
.gdbinit Makefile.in apachenw.mcp.zip include
ABOUT_APACHE Makefile.win build libhttpd.dsp
Apache.dsw NOTICE buildconf modules
BuildAll.dsp NWGNUmakefile config.layout os
BuildBin.dsp README configure server
CHANGES README-win32.txt configure.in srclib
INSTALL README.platforms docs support
InstallBin.dsp ROADMAP emacs-style test
LAYOUT VERSIONING httpd.dsp
(格納されているファイル名一覧が出る)
% tar jxpf httpd-2.2.13.tar.bz2 httpd-2.2.13/IN tab
% tar jxpf httpd-2.2.13.tar.bz2 httpd-2.2.13/INSTALL
([3] 第1引数にサブコマンドを要求するものの補完)
linux# aptitude Tab
autoclean -- erase old downloaded package files
changelog -- view a package's changelog
clean -- erase downloaded package files
download -- download the .deb file for a package
forbid-version -- forbid aptitude from upgrading to a specific package version
forget-new -- forget what packages are "new"
:
:
(以下省略)
linux# aptitude IN Tab
linux# aptitude install vir Tab
("vir"で始まるパッケージのうちインストールしていないものが候補となる)
virsh virtualbox
virt-goodies virtualbox-2.0
virt-manager virtualbox-2.2
virt-top virtualbox-ose
virt-viewer virtualbox-ose-dbg
virtaal virtualbox-ose-guest-source
virtinst virtualbox-ose-guest-utils
virtual-mobile-builder virtualbox-ose-source
virtual-mysql-client virtualbox-source
virtual-mysql-server viruskiller
linux# aptitude rem Tab
linux# aptitude remove
linux# aptitude vir Tab
linux# aptitude remove virtualbox-3.0
(aptitude remove の場合は、
"vir"で始まるパッケージのうちインストールしてあるものが候補となる.
apt-get、yum や、BSD系の pkg_* なども知的補完が組み込まれている)
% svn Tab
Completing svn command
add commit import mergeinfo proplist switch
blame copy info mkdir propset unlock
cat delete list move resolve update
changelist diff lock propdel resolved
checkout export log propedit revert
cleanup help merge propget status
(Subversionのサブコマンド一覧)
% hg Tab
add export locate qfinish qrestore showconfig
addremove forget log qfold qsave status
annotate glog manifest qgoto qselect strip
archive grep merge qguard qseries tag
backout heads outgoing qheader qtop tags
bisect help parents qimport qunapplied tip
branch identify paths qinit recover transplant
branches import pull qnew remove unbundle
bundle incoming push qnext rename update
cat init qapplied qpop resolve verify
clone kwdemo qclone qprev revert version
commit kwexpand qcommit qpush rollback
copy kwfiles qdelete qrefresh root
diff kwshrink qdiff qrename serve
(Mercurialの場合は ~/.hgrc でロードしている拡張モジュールによって
サブコマンドが増えるがそれらを自動検出して補完候補としている)
現在普及しているコマンドはzshの補完関数が既に用意されていると思ってよいだろう。どのコマンドの補完に対応しているかをざっと見たい場合は、zshをインストールしたトップディレクトリ($PREFIX)から見たshare/zsh/バージョン番号 /functions/
ディレクトリにあるファイル一覧を眺めるか、compinit
で補完システムを有効化したzshが起動済みであれば、以下のようにすれば確認できる。
% echo ${(F)${(uo@)_comps}}|less
($_comps の値を見やすく加工して出力)
もし、標準でzshが対応していないコマンドの引数を補完させたい場合は自分で定義することになるが、これについては簡単な補完関数の作り方を後述する。
補完方式の選択
主役となる補完キーTab に標準で割り当てられているのはexpand-or-complete
で、これは単語の展開と通常の補完を行なう。ここでいう「通常補完」とはいわゆるインクリメンタル補完で、入力された文字列が一意に定まる直前までは漸次的に補完して行くものである。
インクリメンタル補完はユーザに確実に正しい単語を選ばせるためには有用だが、似たような名前のファイルが複数ある場合にはゴールに辿り着くまでかえってたくさんキーを打たなければならないこともある。
メニュー補完は、それまで入力した文字列にマッチする候補が複数ある場合、それらを順番に提示する方式である。Tab キーを押すごとに順次切り替わるので、似たような名前のファイルがたくさんあるときでもTab だけ押していればそのうち目的のファイルが出てくることから、より怠惰な補完法とも言える。主な補完をインクリメンタル補完からメニュー補完にしたい場合はTab キーの割り当てを以下のようにmenu-expand-or-complete
に変えるとよい。
この場合、Tab の連打で目的候補を通りすぎてしまった場合のために、逆方向に循環するためのreverse-menu-complete
も別のキーに割り当てておくとよい。たとえば以下のように設定しておくと、行きすぎたときにESC Tab (またはESC C-i )で戻れる。
bindkey '^i' menu-expand-or-complete
bindkey '^[^i' reverse-menu-complete
bindkey '^[i' expand-or-complete
また、カメラの画像ファイルのように数字部分しか違いのないファイルを補完するときなどはメニュー補完で目的ファイルに辿り着くには何連打もしなければならないので、むしろ「インクリメンタル補完の方が便利」というケースもある。それらを考慮しexpand-or-complete
とmenu-expand-or-complete
の両方を好きなキーに割り当てて使い分けることでより素早くより手軽に補完できる。
独自コマンド補完の作成
zsh標準で知的に補完されないもの、あるいは標準の補完は厳密で候補が多すぎてかえって不便と感じる、などの場合は自分なりに便利と思える範囲で補完関数を定義して使うことができる。
ここでは、架空のコマンドに対する補完機能を作成つつ、典型的で簡単なものの作り方を解説しよう。
準備
早速独自の補完関数を作成してみよう。その前に、補完時の挙動を分かりやすくするため、以下の2つを実行しておく。/
% zstyle ':completion:*' format '%BCompleting %d%b'
% zstyle ':completion:*' group-name ''
もしサンプルの.zshrc
ファイル を利用している場合は既に入っているはずなので以下のようにして確認する。
% zstyle -L
では、定義に進む。
例題
コマンドライン引数で様々なオプションを指定して利用する流儀のコマンドの引数補完を定義してみよう。ここでは架空のコマンドgizの補完定義を試みる。gizコマンドは以下のようなコマンドライン文法を取るものと仮定する。
% giz
Usage: giz [ -fnqv ] [ -g grp ] [ -d {foo|bar|baz} ] file
Possible options are as follows:
-f Force overwrite
-n No exec, echo only
-q quiet
-v verbose
-g grp set group to grp
-d kwd set default keyword to kwd, which is one of:
foo, bar, baz
架空の例なので、Usageの文には全く意味がないが、補完定義をする立場から
文法的な特徴のみ記すと以下のようになる。
第1引数にはファイル名を指定する
オプションには以下のものがあり、基本的には全て1字オプションである。
-f, -n, -q, -v の単体オプション
引数を1つ取る -g, -d オプション
-q オプションと -v オプションは意味が反対なので同時に指定しても(間違いではないかもしれないが)意味がない
このような形式のコマンドをコマンドライン入力するときに、
% giz
あるいは、
% giz -
のようなカーソル位置で補完キー(Tab)を押したときの挙動を制御したい。
_arguments
関数
典型的なコマンドラインオプション・引数の補完処理を包括的に司るのが、zsh補完システムに用意された_arguments
関数である。
_arguments
関数で補完できるようになるコマンドライン文法は幅広く非常に有用なのだが、_arguments
関数そのものの利用を完全に把握するためには膨大な事前知識を要する。そのためここでは典型的なコマンドライン文法を持つ、前述の架空コマンドgizの補完定義例を示し、同様のコマンド補完が定義できるようになることを目指そう。
先に定義例を示すと、gizの補完ができるようになる関数定義は以下のようになる。
function _giz () {
_arguments -s : \
'-f[Force overwrite]' \
'-n[No exec]' \
'(-v)-q[Quiet]' \
'(-q)-v[Verbose]' \
'-g[Group]:group:_groups' \
'-d[Keyword]:keyword:(foo bar baz)' \
'1:file:_files'
}
コマンドラインでも上記のとおり入力すれば、_giz
関数が定義できすぐに利用できる。まずは実際に動かしこの関数定義による補完挙動を理解しよう。実際に機能させるには以下のようにcompdef
コマンドで補完定義を補完したいコマンドに割り当てる。
% compdef _giz giz
実際にコマンドラインのコマンド位置にgiz
を入力し、引数位置でいろいろ補完候補を示した例を示す。
% giz
(通常引数位置での補完候補)
% giz ESC C-d
Completing file
tetris.html z-1.html z-3.html z-5.html
tetris.png z-2.html z-4.html z-anecdote.html
(ハイフンの直後での補完候補)
% giz - ESC C-d
Completing option
-d -- Keyword
-f -- Force overwrite
-g -- Group
-n -- No exec
-q -- Quiet
-v -- Verbose
(-fオプション入力後の補完候補からは-fが消える)
% giz -f ESC C-d
Completing option
-d -- Keyword
-g -- Group
-n -- No exec
-v -- Verbose
-q -- Quiet
(-gオプションを入れた後の補完候補)
% giz -f -g ESC C-d
Completing group
_httpd _sdpd daemon guest named operator staff utmp
_pflogd _timedc dbus kmem nobody polkit sys wheel
_proxy authpf dialer mail nogroup postfix tty wsrc
_rwhod bin games maildrop ntpd sshd users
(システムに存在するグループ一覧が出力される)
その他、引数を分けて書いたりいろいろと実験してみよう。
_arguments
関数の引数指定
gizの補完の挙動が分かったところで、_arguments
関数への引数指定を紐解いていこう。
_arguments -s : \
'-f[Force overwrite]' \
'-n[No exec]' \
'(-v)-q[Quiet]' \
'(-q)-v[Verbose]' \
'-d[Keyword]:keyword:(foo bar baz)' \
'-g[Group]:group:_groups' \
'1:file:_files'
このコードの意味は以下のとおり。
1行目:
-s
オプションは、補完対象となるコマンドの1字オプションをまとめて記述できることを指示する。たとえば、gizコマンドの-f
オプションと-n
オプションを同時に指定するのに-fn
と書け、これを補完入力するときにも-f
と入力したすぐ後ろの位置で他のオプション文字を補完するようにふるまう。
:
は_arguments
関数自身へのオプションがここで終わることを明示する。
2行目、3行目:
-f[Force overwrite]
の部分は、gizコマンドのオプション(のうち補完したいもの)に-f
があり、補完候補提示時のコメント文を `Force overwrite' にすることを指示している。3行目の -n[No Exec]
も同様。
4行目、5行目:
(-v)-q[Quiet]
の -q[Quiet]
の部分は2、3行目と同様で補完したいオプションに-q
があり、その説明文が `Quiet' であることを指示する。その前に付いている(-v)
はこのオプションの補完を-v
オプションと排他的にすることの指示である。
この例のように(-v)-q
と書いた場合、以下のことを指示する。
-q
オプションが既にコマンドライン上にある場合、それより後ろでは-v
オプションを補完候補から外す
括弧内には除外したいものを空白区切りで複数書ける。
6行目:
-d[Keyword]:keyword:(foo bar baz)
の部分はコロンで区切られた3つのフィールドから成っている。最初の -d[Keyword]
は上記同様-d
オプションの補完登録である。第2フィールド以降の指定はそのオプションに対する引数があることを示し、第2フィールドにはオプション引数補完入力時のメッセージを、第3フィールドにはその補完候補の生成法を指定する。この例の (foo bar baz)
のように括弧内に空白区切りの単語を書いた場合は、その単語を候補とする。
% giz -d ESC C-d
Completing keyword
bar baz foo
7行目:
'-g[Group]:group:_groups'
も6行目と同様の「オプションとそのオプションに対する引数」の補完定義である。最後にある_groups
は補完関数の名前で、第3フィールドに関数名を指定するとその関数によって補完候補を入力するようになる。_groups
関数はその名前が示すとおり、システムに存在するグループ名を候補として補完入力させる。
8行目:
'1:file:_files'
は第1フィールドが自然数で始まっている。これはその位置での通常引数の補完方法を指定する。通常引数とはオプションやオプションへの引数を除いた引数で、たとえば以下のようなコマンドラインの場合、
% rsync -a --delete -e 'ssh -4' remote:foo bar
'ssh -4'
までの部分はすべてオプションやオプションへの引数と考え、通常引数は、第1引数がremote:foo
、第2引数がbar
となる。
_giz
関数の例の'1:file:_files'
の場合は通常の第1引数入力時には、`file
' というメッセージを出し、実際の単語を_files
関数で補完入力させることを指示している。
補完定義のオートロード化
補完入力時の効果が確認できたら、次回ログイン時も有効にするための設定を行なおう。
手順は以下のとおりに進める。
ファイルを保存するzshスクリプト用のディレクトリを決める
そのディレクトリをシェル変数 fpath
に設定する
補完用関数定義を関数と同名のファイル名で保存
ここでは仮に、保存ディレクトリを~/script/zsh
に決めたものとして説明する。
% mkdir -p ~/script/zsh
このディレクトリに置いた関数定義ファイルを自動的に読み込むよう、~/.zshrc
のcompinit呼出しより上の部分
に以下の記述を追加する。
typeset -U fpath
fpath=($fpath ~/script/zsh)
これで準備完了。fpath
はzshが利用する変数で、関数のオートロード時に参照するディレクトリを登録するためのものである。オートロード機能とは、実際に関数実行が必要になった時点で関数定義をファイルから読み込ませることができるものである。これまで補完機能の有効化に「autoload -U compinit && compinit
」としていたが、このautoload
が関数のオートロードを宣言するものである。これと同じように独自定義したzsh関数もオートロード化できる。先の例に示した_giz
関数定義を含めた、以下のようなファイルを _giz
というファイル名で作成し、~/script/zsh
ディレクトリに置く。
_giz
ファイル
#compdef giz
function _giz () {
_arguments -s : \
'-f[Force overwrite]' \
'-n[No exec]' \
'(-v)-q[Quiet]' \
'(-q)-v[Verbose]' \
'-g[Group]:group:_groups' \
'-d[Keyword]:keyword:(foo bar baz)' \
'1:file:_files'
}
以上で、次回zsh起動時に_giz
関数定義ファイルが、gizコマンドのコマンドライン補完のタイミングで自動的に読み込まれるようになる。1行目に書いた `#compdef giz
' は、この関数定義ファイルがgiz
コマンドの補完時に使われることを示す特殊記法である。
では、その設定が生きているか確かめるためにzshを再起動しよう。
% exec zsh
コマンドラインで "giz -"
まで入力した位置で補完が働くか確かめよう。
% giz - ESC C-d
Completing option
-d -- Keyword
-f -- Force overwrite
-g -- Group
-n -- No exec
-q -- Quiet
-v -- Verbose
関数作成の試行錯誤
定義した関数でうまく補完できることが分かったら、今度はそれを改良したくなるもの。関数定義を修正してはロードし直す方法を説明しておく。関数定義をコマンドラインで直接打ち込む段階が完了し、fpath
変数に登録したディレクトリに定義ファイル(上の例では~/script/zsh
)を保存した後、関数のデバッグはファイルをエディタで編集しながらやることになるだろう。その場合、修正してセーブしたら、それを現行zshに反映させるために以下のようにする。
% unfunction _giz; autoload +X _giz
unfunction
は既存の関数定義を抹消する。autoload +X
は、関数のオートロードを直ちに行なう。
様々な補完アクション
上述の_giz
関数定義の7行目:
-g[Group]:group:_groups
の第3フィールド _groups
は補完候補としてグループ名を選ぶものであった。このようにzsh標準装備の関数で補完できるものがいくつかある。代表的なものを表に示しておく。
関数 補完される語の種別
_aliases
エイリアス
_builtin
内部コマンド
_groups
グループ
_files
ファイル
_functions
関数名
_gnu_generic
--help
オプションを受け付けるもの
_hosts
ホスト名
_parameters
変数名
_precommand
time や eval のように引数にコマンドラインを伴うもの
_users
ユーザ名
_user_at_host
USER @HOST の形式
その他様々な補完形態を取り扱う関数が多数あり、それらはオンラインマニュアル zshcompsys(1) で参照可能だが、マニュアルから読み解くのはおそらく難解すぎるだろう。標準添付されている関数を真似して行くのが早道ではないだろうか。
その先へ
zshは標準で準備されている機能が豊富である。そしてそれらは同時にとことんカスタマイズ可能である。ちょっと感じた面倒を見逃さず調整して行くことで最高に気のきく、しもべを得ることができるだろう。
もちろんあまりカスタマイズを意識しなくとも、細かい気配りが行き届いていて十分に便利であることは間違いない。そして何より、shの制御構造や変数展開などの構文をコマンドラインで使用しても、正確に補完でき、不自由なくヒストリ呼出しや行編集ができるので積極的に利用することでシェルスクリプトの知識がどんどん身に付きスキルアップに繋がるという点は隠れた大きなメリットと言える。これを機会にぜひzshの世界へ飛び込んでみてほしい。