Edited at

.zshrcで見かけるautoloadの意味と使い方

More than 5 years have passed since last update.

.zshrcにこういうのありませんか?

autoload -U compinit

今回はこの autoload が何をするものなのか解説します。


autoloadはシェル関数を読み込む

autoload はシェル関数を 自動読み込み するシェルの組み込み関数です。上記のスクリプトの場合、 compinit というシェル関数を自動読み込みします。

シェルコマンドは PATH に入っていればそれだけで実行可能でしたが、シェル関数の場合は関数を定義しなければ使えません。 autoload はファイルシステム上にある関数定義を読み込むための関数なのです。そして autoload 探索するディレクトリは FPATH に入っています。

余談ですが FPATH だと : 区切りの文字列、 fpath だと配列になります。PATHpath と同じですね。


autoloadを使ってみる

% mkdir ~/functions

% FPATH="${HOME}/functions:${FPATH}" # ~/functionsをfpathに登録
% cat << EOF > ~/functions/test-func
#!/bin/zsh
echo Hello autoload
EOF
% ls ~/functions
. .. test-func

test-func という関数をfpathに登録したので実行してみます。

% where test-func

test-func not found
% autoload test-func
% where test-func # (1)
test-func () {
# undefined
builtin autoload -X
}
% test-func
Hello autoload
% where test-func # (2)
test-func () {
echo Hello autoload
}

たしかに ~/functions/test-func の中身を持つ関数が作られました。

ところで (1) で表示される関数の中身がなんかおかしいですね。 builtin は引数を強制的に組み込み関数名として解釈する関数なので、結局 autoload -X をやっているだけですが、意図したものとは異なります。一方で一回関数を実行した後の (2) になると意図したものになっています。

実はこの -X オプションがない場合、 autoload コマンドは autoload という名前にも関わらず関数を登録するだけで、実体をロードしません。そして -X があると、関数を実際にロードしてかつ即座に実行します。つまり、こうすることでzshは関数を遅延読み込みしているわけですね。

# 下の2行は即座に実行される点で同じ

autoload test-func; test-func
autoload -X test-func # 余計な中間関数がないので若干効率的

ロードだけして実行しない場合は +X オプションを使います。先ほどの test-func がまだロードされていない状態だとすると

% where test-func

test-func not found
% autoload +X test-func # ロードする
% where test-func # ロード済みになっている
test-func () {
echo Hello autoload
}

-X+X オプションは覚えなくていいですが、zshrcでいくら autoload しようが立ち上がり速度にはそこまで影響がない、ということは覚えておいて損は無さそうです。


-Uオプション

冒頭のコマンド

autoload -U compinit

ですが、この -U オプションは一体何の働きをするのでしょう?個人的な観測範囲でいえば autoload-U を使っていない場面をみたことがありません。

実はこのオプションは、展開される関数の内部で alias の展開を しない ためのオプションです。つまり、これがないとあなたが適当に作ったalias が干渉して、関数の動作が変わってしまう危険があるので、それを回避するために使うのです。

% alias foo='echo bar'

% cat << EOF > with-U > without-U
foo
EOF
% autoload -U with-U; with-U
zsh: command not found: foo
% autoload without-U; without-U
bar

というわけで autoload を使うときは 必ず -U オプションを使った方がよさそうです。

ちないに -U-X は同時には使えないみたいです。なので -U してかつ即座に実行したい場合は下記のようにしなければいけません。

autoload -U funcname; funcname

-X オプションの説明に、シェルスクリプト内部でしか使うことないと思う、みたいなことが書いてあって、たぶんここら辺の事情が関係しているんだと予想してます。


もうちょっと追いかけてみる

autoload みたいな組み込み関数についてのマニュアルは zshbuiltins(1) にあります。それによると


-X, +X, -w なしの functions -u と等しい


とあります。そして functions


-M なしの typeset -f と等しい


つまり autoloadtypeset -fu と等しい、ということになります。そもそも typeset が何をするのかというと、簡単な話が変数宣言です。

例えば環境変数を設定する exporttypeset -gx と同じです。 -g はグローバルフラグで、 -x は宣言した変数が環境変数であることを意味します。これによって宣言された変数が環境変数として外部からも利用可能になります。

で、問題の typeset -fu ですが、 -f は関数(function)である、という意味で -u は(-f と一緒に使っている場合)その関数を自動読み込み(autoloading)する、という意味です。

なるほどなるほど


合わせて読みたい


  • zshmisc(1) の AUTOLOADING FUNCTIONS

  • zshbuiltins(1)