我正在尝试了解 Bash 变量插值。
我想用来readlink
显示符号链接指向的路径。
如果我使用字符串它就可以工作。
$ echo "$(readlink -- ~/.gitconfig)"
/Users/jord/.dotfiles/gitconfig
由于某种原因,当我尝试使用变量而不是字符串时它不起作用。
$ file="~/.gitconfig"
$ echo "$(readlink -- $file)"
除空白行外,不打印任何内容。
如果我做同样的事情,但用dirname
(作为示例),变量插值就会按我预期的方式工作。
$ file="~/.gitconfig"
$ echo "$(dirname -- "$file")"
~
我究竟做错了什么?
答案1
~
~
引号中的Bash 参考手册的相关部分以。。开始
如果单词以不带引号的波浪符号 (
~
) 开头,则...
要查看差异,请比较:
file="~/.gitconfig"
echo "$file"
file=~/".gitconfig"
echo "$file"
在您的第一个示例中,$(…)
first 起作用,并且在其上下文中~
未加引号。因此,它会按预期进行扩展。
$file
当它“不起作用”时,您的包含文字~
。POSIX 标准称:
字扩展的顺序如下:
波浪符号扩展 […]、参数扩展 […]、命令替换 […] 和算术扩展 […] 应从头到尾执行。[…]
由于波浪号扩展是在参数扩展之前执行的,因此扩展到的变量~/something
不会进一步扩展到正确的路径。
请记住,在某些情况下~
,或对于~/
您的 shell 来说是特殊的,但对于(几乎?)任何其他工具来说,它都不是有效路径。当它起作用时,这是因为 shell 首先发挥了它的“魔力”,而其他工具看到了已经扩展的路径(例如/Users/jord
)。
请注意你最后一个例子中的波浪符号扩展没有工作,您仍然会得到文字~
,而且对于 shell 来说,如果不使用额外的技巧(例如eval
),就无法对其进行处理。dirname
不会出现任何问题,因为它适用于字符串。它不关心给定的路径是否有效、是否存在等。它基本上只是搜索最后一个非斜杠组件并将其与尾随斜杠一起丢弃(如果有)。
也可以看看这个答案。