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

  • 89
    Like
  • 0
    Comment
More than 1 year has 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 しないようにすればもっと便利になると思うので試してみてください!