如何在ZSH中编辑路径变量

23

在我的.bash_profile文件中,我有以下几行代码:

PATHDIRS="
/usr/local/mysql/bin
/usr/local/share/python
/opt/local/bin
/opt/local/sbin
$HOME/bin"
for dir in $PATHDIRS
do
    if [ -d $dir ]; then
        export PATH=$PATH:$dir
    fi
done

然而我尝试将这个命令复制到我的.zshrc文件中,但是$PATH没有被设置。

首先我在“如果目录存在”函数中放置了echo语句,发现即使对于明显存在的目录,if语句也会评估为false。

然后我删除了目录存在检查,$PATH被错误地设置成如下形式:

/usr/bin:/bin:/usr/sbin:/sbin:
/usr/local/bin
/opt/local/bin
/opt/local/sbin
/Volumes/Xshare/kburke/bin
/usr/local/Cellar/ruby/1.9.2-p290/bin
/Users/kevin/.gem/ruby/1.8/bin
/Users/kevin/bin

底层目录中的程序都没有被找到或执行。
我做错了什么吗?

3个回答

49

与其他的shell不同,zsh在变量替换后并不执行单词分割或者globbing。因此,$PATHDIRS会扩展为一个包含变量值完整内容的字符串,而不是一个包含每个由空格分隔的独立部分的字符串列表。

使用数组是表达这个概念的最佳方式(不仅在zsh中,也适用于ksh和bash)。

pathdirs=(
    /usr/local/mysql/bin
    …
    ~/bin
)
for dir in $pathdirs; do
    if [ -d $dir ]; then
        path+=$dir
    fi
done

既然你后面可能不会再引用pathdirs,那么最好行内直接写出:

for dir in \
  /usr/local/mysql/bin \
  … \
  ~/bin
; do
  if [[ -d $dir ]]; then path+=$dir; fi
done

有一种更短的表达方式:将你喜欢的所有目录添加到path数组中,然后选择存在的目录。

path+=/usr/local/mysql/bin
…
path=($^path(N))

N通配符限定符只选择存在的匹配项。如果担心某个元素可能是目录或符号链接以外的其他内容(例如,损坏的符号链接),则将-/添加到限定符列表中(即(-/N)(N-/))。^ 参数展开标志确保通配符限定符分别应用于每个数组元素。

您还可以使用N限定符仅在存在时添加元素。请注意,需要进行通配符扩展,因此path+=/usr/local/mysql/bin(N)无法工作。

path+=(/usr/local/bin/mysql/bin(N-/))

11
+1 - 对于在 zsh 中进行 $PATH 操作的人来说,以下两个额外的快速提示可能会很有用:*(1)* 如果要在前面添加而不是追加,请使用 path[1,0]=/path/to/dir,和 (2) 如果您正在使用 globbing 查找目录,则无需使用 for 循环,只需执行 path+=( $PWD/node_modules/**/bin ) 即可(也适用于 (1) )。 - unthought
谢谢,我使用了你的建议,路径为path=($^path(N-/))。 现在有没有办法确保每次运行source ~/.zshrc时,$PATH中不会重复出现相同的目录? - stansult
@unthought 非常喜欢你的预先添加 (foo [1,0] = bar) 的技巧。真是个爱搞晦涩的家伙! - Alex Gray

5

您可以放置

 setopt shwordsplit

在你的.zshrc文件中添加以下内容。然后,zsh将像所有Bourne shell一样执行单词拆分。默认值似乎是noshwordsplit,这是一个错误,会导致很多人感到困惑。如果不是常见问题解答,我会感到惊讶。让我们看看...是的:http://zsh.sourceforge.net/FAQ/zshfaq03.html#l183.1:为什么$var,其中var =“foo bar”不按预期工作?

3

我仍然不确定问题出在哪里(也许是$PATHDIRS中的换行符?),但更改为zsh数组语法可以解决它:

PATHDIRS=(
/usr/local/mysql/bin
/usr/local/share/python
/usr/local/scala/scala-2.8.0.final/bin
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/bin
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin
/opt/local/etc
/opt/local/bin
/opt/local/sbin
$HOME/.gem/ruby/1.8/bin
$HOME/bin)

并且

path=($path $dir)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接