分岐の zsh っぽい書き方

  • 37
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

zsh でスクリプトを書くときに、他のシェルでの書き方に慣れていると、せっかくの持ち味である豊富な文字列処理を持て余すことになる。

例えば、こんな処理があったとする。

if which tac >/dev/null 2>&1; then
    tac="tac"
else
    tac="tail -r"
fi

peco などのスクリプトを書くときによくみるやつだ。tac は GNU/Linux ではほとんどのケースでインストールされているものの、他の環境では自分でインストールする必要が有るためこのような処理が必要となるのだが・・・

これを zsh らしく書くとこうなる。

tac=${commands[tac]:-"tail -r"}

そう、たった 1 行、zsh ならね。

やっていることは簡単である。

  1. 連想配列 commands に tac というキーが有るかどうかチェックする
  2. なければ空なので、空の場合に処理をする ${foo:-bar} を利用する

commands は tac があれば tac をキーにそのフルパスが得られる、システムで宣言されている連想配列である。

$ echo $commands[tac]
/usr/local/bin/tac

一度、echo $commands としてみれば大量のコマンドがバリューとして登録されているのがよく分かる。

またこのような分岐ではなくとも、commands を利用した書き方は便利で、

if (( $+commands[tac] )); then
    echo "tac: available"
fi

とすれば tac があるかどうか、をチェックすることができる。

これはどういうことかというと $+foo[bar] 変数 foo が空でなければ 1、空であれば 0 が返る指定子の + を使ったものである。

$ echo $+commands[tac]
1

if (( 1 )); then に展開されるので、もちろん真となる。

このように通常のシェルスクリプト(sh や bash)を書いている人が zsh を書くと zsh らしさが消えたスクリプトになる。それ自体は悪いことじゃない。ポータブルで汎用的なシェルスクリプトを書く場合、POSIX な書き方を意識するのが重要だからだ。しかし、zshrc 内など zsh 上で実行することを前提したケースにおいてまで、そんな書き方をする必要はない。おそらく zstyle など、どうせ zsh でしか動かないような記述箇所があるのだから。それにその場合にまで固執し過ぎると zsh を使っている意味が無い。zsh を使っているのならふんだんにその便利な書き方を使っていくべきである。

この投稿は zsh Advent Calendar 201512日目の記事です。