众所周知,路径的任何组件中都可以包含换行符。
那么我们是否应该得出结论,环境变量$PATH
可以包含换行符?
如果是这样,如何将 拆分$PATH
为其元素,类似于(Bourne like):
IFS=':' ; set -f
for var in $PATH
do
echo "<$var>"
done
但如果可以在不改变 IFS 的情况下完成,那就更好了。
答案1
在 POSIX shell 中,$IFS
是一个字段分隔符,而不是分隔符,因此$PATH
像这样的值/bin:/usr/bin:
将被拆分为/bin
和/usr/bin
而不是/bin
,/usr/bin
以及空字符串(表示当前目录)。你需要:
IFS=:; set -o noglob
for var in $PATH""; do
printf '<%s>\n' "$var"
done
为了避免修改全局设置,您可以使用带有显式拆分运算符的 shell,例如zsh
:
for var in "${(s/:/@)PATH}"; do
printf '<%s>\n' "$var"
done
尽管在这种情况下,数组zsh
已经$path
绑定到/$PATH
中,所以:csh
tcsh
for var in "$path[@]"; do
printf '<%s>\n' "$var"
done
无论如何,是的,理论上$PATH
就像任何变量都可以包含换行符一样,换行符在文件路径解析方面并不特殊。我不希望任何明智的人会在其$PATH
名称中放置带有换行符(或通配符)的目录或命名带有换行符的命令。也很难想象有人可以利用一个假设$PATH
不包含换行符的脚本的场景。
答案2
是的,PATH
可以包含换行符(即使在古老的 Unix 系统上)。
至于在 shell 中分割任何字符串,唯一可以移植的方法是使用IFS
.不过,您可以使用IFS=:; set -f; set -- $PATH
它或将其传递给函数for
,而不是使用 循环。
您bash
还可以将字符串“读”入大批:
xtra=$'some\nother\nplace\n\n'; PATH="$PATH:$xtra"
mapfile -td: path < <(printf %s "$PATH")
printf '<%s>\n' "${path[@]}"
但使用数组通常不是一个好主意,因为它们不能透明地存储在环境变量中或作为单个参数传递给外部命令。
请注意,这IFS
将终止字段,而不是分隔它们(有点像\n
文件末尾不会被逐行读取文件的程序视为空行);如果这不是预期的结果,并且您确实希望在拆分以 中的字符结尾的字符串时在末尾创建一个额外的空字段IFS
,则应该在要进行单词拆分的变量后面加入一个空字符串:
(P=/bin:; IFS=:; printf '<%s>\n' $P"")
</bin>
<>
IFS
如果这些空白字符是 的一部分,分词算法还将忽略字符串开头的空白字符。如果您想要一个额外的字段作为前导空格,您还应该在变量之前加入一个空字符串:
(P=' foo : bar '; IFS=': '; set -f; set -- $P; printf '<%s>\n' "$@")
<foo>
<bar>
(P=' foo : bar '; IFS=': '; set -f; set -- ""$P""; printf '<%s>\n' "$@")
<>
<foo>
<bar>
<>