Posted at
zshDay 13

zsh で source して使うプラグインを作るのは止めにしよう

More than 5 years have passed since last update.

zsh のシェルスクリプトを作るとき、基本的には普通のシェルスクリプトとして書く。「普通」というのは、1行目に #!/bin/zsh と書いてあって、今のシェルとは別プロセスで動かすスクリプトのことだ。

例えばこんな感じ。


script_sample.zsh

#!/bin/zsh

echo "Hello World"

# 使うとき

% chmod 755 script_sample.zsh
% ./script_sample.zsh
Hello World

でも、そうではなくて source して使うスクリプトを書くことがある。


source_sample.zsh

homecd () {

cd
ls

}

# 使うとき

% source source_sample.zsh
% homecd
Desktop/ bin/ local/ tmp/ vimfiles/
Dropbox/ etc/ var/ work/

特に、cd や bindkey など、今動いているシェル上で副作用のある処理を行いたいときは source を使わないとうまくいかないだろう。

一方、source にはこんなデメリットがある。


  • .zshrc でいっぱい source するとzsh の起動が遅くなる

  • 現在動いているシェルの alias 設定の影響を受ける

特に2つめが厄介だ。例えば grep とかしたときに、alias grep='grep -E' なんか設定してあったら正規表現の意味が変わってしまう。一応 command grep とすれば alias を設定していない元の grep を実行できるけど、いちいちそう書くのも手間だ。

そんなときは autoload を使う形に書き換えるとうまくいく。

autoload というのは「関数本体の読み込みを実行する時まで遅らせる」という zsh の機能のこと。これで ~/.zshrc にいっぱい書いても起動が遅くならないですむ。さらに alias を無効する(現在の alias の影響を受けない)ようにもできる。これで変なことを気にしなくて良くなるので、関数が書きやすくなる。


基本的な例

まずは hello_autoload という名前の関数を autoload する例を見てみる。

まず、以下の内容でファイルを作成する。ファイル名は hello_autoload とする。このファイル名が実際に実行するときの関数名になる。


hello_autoload

echo "Hello Autoload!"


普通、関数の定義は

hello_autoload () {

# 関数の中身
}

みたいに書くんだけど、 autoload するときは関数の中身だけ書くことに注意する。

この hello_autoload ファイルを $fpath の通ったところに配置すれば準備完了。

後は ~/.zshrc で autoload して、


.zshrc

autoload hello_autoload


使いたい時に呼びだせば OK。

% hello_autoload

Hello Autoload!


実践的な例

次は実際にプラグインっぽく作るときの書き方を見てみる。今回は「指定したディレクトリに移動して ls する」という関数を作ってみる。名前は cdls にする。

cdls という名前で次のファイルを作成する。


cdls

cd $1

ls

ファイルを置く場所はどこでもいいんだけど、今回は ~/zsh/functions/Cdls/ とした。ディレクトリ名も何でもいいんだけど、慣習として先頭は大文字にするようだ。

次に .zshrc で fpath を通して autoload する。


.zshrc

fpath=(~/zsh/functions/*(N-/) $fpath)

autoload -Uz cdls


autoload-U-z というオプションを指定してる。

-U は、呼び出し側のシェルで alias 設定を設定していたとしても、中の関数側ではその影響を受けなくなるというオプション。ls は alias を設定してることが多いと思うけど、この場合はそのままの ls が実行される。

-z は関数を zsh 形式で読み込むというオプション。代わりに -k を指定すると ksh 形式で読み込むようになる。普通は zsh 形式で関数を書くので -z と指定しておけば問題ない。

後は適当に source ~/.zshrc して、使いたい時に呼び出すだけだ。

% cdls

Desktop Dropbox bin etc local tmp var vimfiles work
% pwd
/home/mollifier

% cdls ~/work
github-sandbox javascript nodejs scala vim zsh
% pwd
/home/mollifier/work

うまくいってる。

これ以降、autoload が必要なスクリプトを追加するときは同じように ~/zsh/functions/ の下にディレクトリを作って配置すれば良い。

fpath=(~/zsh/functions/*(N-/) $fpath) という設定をしているので、~/zsh/functions/ の下にディレクトリがあればそこに勝手に fpath が通るようになってる。なので fpath の設定は書きなおさなくても OK。

こんな感じで source しないようにすればもっと便利になると思うので試してみてください!