路径中的波浪号(~)不能展开到主目录

25
假设我有一个名为 Foo 的文件夹,位于 /home/user/(我的 /home/user 也可以用 ~ 表示)。
我想要创建一个变量 a="~/Foo",然后执行 cd $a。但是会出现错误信息 -bash: cd: ~/Foo: No such file or directory
然而,如果我只执行 cd ~/Foo 就能正常工作。有没有办法让这个变量也正常工作呢?

3
可能会对这里的人感兴趣:如何在bash中手动扩展特殊变量(例如波浪号)。我强烈建议您不要使用任何回答,无论是在此问题中还是其他地方,这些回答指导您使用eval;请参见BashFAQ#48 - Charles Duffy
5个回答

30

你可以这样做(在变量赋值时不使用引号):

a=~/Foo
cd "$a"

但是在这种情况下,变量$a将不会存储~/Foo,而是展开形式/home/user/Foo。或者您可以使用eval

a="~/Foo"
eval cd "$a"

谢谢!eval cd 命令起作用了。我确实想保留“~/Foo”的完整性,所以这个解决方案可行。起初我尝试了cd `eval $a` 但那没起作用。 - Benjamin
7
在这里,对使用eval的一般警告也应该被突出标记。绝对不要在未经过净化或以安全方式构建的数据上运行eval - tripleee
2
不幸的是,如果目录名包含空格,则此方法无法正常工作。 a="〜/带有空格的目录"; eval cd“$a” => -bash:cd:/Users/jack/dir:没有那个文件或目录 :-( - duthen
@duthen:你可以使用有点丑陋的变体 cd "$(eval echo "$a")" - bmk
正确的编写方式是 a=~/dir\ with\ spaces 或等价的 a=~/"dir with spaces" - tripleee

18

您可以使用$HOME替代波浪线(波浪线由shell扩展为$HOME的内容)。

示例:

dir="$HOME/Foo";
cd "$dir";

1
如果你的名字不是“约翰F.”,引号有什么好处?分号又是为什么? - user unknown
感谢您提到波浪号实际上扩展为$ HOME,我认为这更易读。 - DusteD
3
如果省略引号,就是在告诉终端要“做更多的事情”,而这些事情都有可能失败。例如,如果有人设置 IFS=/ 以读取斜杠分隔的输入,则即使没有空格,cd $dir 也会出现问题。未加引号地扩展字符串会告诉终端对其进行字符串拆分和通配符扩展。为什么要编写指导终端执行不想执行的操作的代码呢? - Charles Duffy

1
一个更加强大的解决方案是使用像sed或者更好的bash参数扩展这样的工具。
somedir="~/Foo/test~/ing";
cd "${somedir/#\~/$HOME}"

或者如果你必须使用sed,

cd $(echo "$somedir" | sed "s#^~#$HOME#")

不幸的是,如果您尝试引用其他人的主目录,则此方法将无法正常工作。 somedir="~jack/TMP"; cd ${somedir/#\~/$HOME} => -bash: cd: /Users/jackjack/TMP: No such file or directory :-( - duthen

1
尽管这个问题只是要求一个解决方法,但它被列为许多询问为什么会发生这种情况的问题的重复,所以我认为值得给出一个解释。根据https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06
引用: 单词扩展的顺序如下: 波浪号扩展、参数扩展、命令替换和算术扩展应该从开始到结束执行。
当shell评估字符串cd $a时,它首先执行波浪号扩展(这是无操作,因为$a不包含波浪号),然后将$a扩展为字符串~/Foo,这是最终作为参数传递给cd的字符串。

-1

如果您使用双引号,那么~将保留为$a中的字符。

cd $a不会扩展~,因为shell不会扩展变量值。

解决方案是:

eval "cd $a"


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