Help us understand the problem. What is going on with this article?

zsh で path にディレクトリを追加するときは (N-/) を付けよう

More than 5 years have passed since last update.

はじめに

.zshenv とかで path にディレクトリを追加するとき、こんなふうに普通に追加してる人がいると思う。

# path の先頭に $HOME/bin を追加する(あんまり良くない例)
path=($HOME/bin $path)

これでも間違いというわけではないんだけど、追加するディレクトリが存在しない場合も path に追加されて、結果として無駄なディレクトリが含まれている状態になってしまう。あんまりうれしくない。

でも zsh にはちゃんとそれを防ぐ方法があって、ディレクトリ名の後ろに (N-/) を付ければうまく解決できる。

# 良い例
path=($HOME/bin(N-/) $path)

これで $HOME/bin が存在しているときだけ path に追加する、という動作になる。

ディレクトリを複数同時に追加するときも同じように並べて書けば OK。

path=($HOME/bin(N-/) /usr/local/bin(N-/) $path)

解説

なんにも考えずにコピペで使ってもいいんだけど、もうちょっと詳しく説明してみる。

この (N-/) はファイル名修飾子というやつで、ファイル名に条件つけて絞り込みができるようになる。この場合は N, -, / という3つの条件を指定してる。

まず / というのは「ディレクトリだけ」という意味で、ディレクトリが存在するときだけ () の左側の値に展開される。

# /tmp というディレクトリ、/etc/passwd という通常のファイルが存在するとする

# 存在するディレクトリ名は OK
% echo /tmp(/)
/tmp

# 存在しないディレクトリの場合はエラーになる
% echo /hoge(/)
zsh: no matches found: /hoge(/)

# ディレクトリじゃなくて通常ファイルの場合もエラーになる
% echo /etc/passwd(/)
zsh: no matches found: /etc/passwd(/)

で、N を付けるとマッチしない(ディレクトリが存在しない)時にエラーの代わりに黙って空文字列に展開されるようになる。

# ディレクトリが存在する場合は N 無しと同じ
% echo /tmp(N/)
/tmp

# ディレクトリが存在しない場合は空文字列
% echo /hoge(N/)

これを使うと $HOME/bin が存在しない状態で path=($HOME/bin(N/) $path) とした時に $HOME/bin(N/) の部分が空文字列になるので、結果として path には何も追加されない、という動作になる。

これでだいたい問題ないんだけど、$HOME/bin がシンボリックリンクだったときに困る。$HOME/bin がシンボリックリンクで存在するディレクトリを指している場合は本当は path に追加して欲しいんだけど、(N/) は「ディレクトリであった場合だけ展開する」という意味なので、空文字列になってしまう。

そういう時のために - っていうのがある。これを付けるとシンボリックリンクの実態を追いかけて条件をチェックするようになる。つまり、(N-/) は「ディレクトリが存在する、またはシンボリックリンクで存在するディレクトリを指している」という条件指定になる。

# $HOME/bin はシンボリックリンクで、$HOME/scripts というディレクトリを指しているとする
% ls -l $HOME
bin -> scripts
scripts/

# $HOME/bin はディレクトリではないので空文字列になる
% echo $HOME/bin(N/)

# - を付けるとシンボリックリンクの実態に対して条件をチェックする
% echo $HOME/bin(N-/)
/home/mollifier/bin

というわけで、結論として (N-/) を付けるとディレクトリが存在するときだけ path に追加する、という動作になる。

path=($HOME/bin(N-/) $path)

こうやっておくと .zshrc をいろんな環境で使いまわす時に変なのが path に追加されなくて便利。path 以外でも fpath とか manpath とかディレクトリを追加する系の環境変数の場合は同じようにしたほうが良いと思う。

if 文とかでチェックしてもいいんだけど、こっちのほうが1行で済んでスマートだと思うのでぜひ試してみてください!

参考

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away