我在测试脚本时发现了一些有趣的事情。
如果我运行,我可以从 shell 手动 ls 我的目录
$ ls ~/db_backups/
test1 test2
$
但是,如果我使用波浪号为 shell 变量分配一个目录位置,则它不起作用。我用单引号和双引号尝试过。
$ backupfolder='~/db_backups'
$ echo $backupfolder
~/db_backups
$ ls $backupfolder
ls: cannot access '~/db_backups': No such file or directory
$
shell 变量内的波形符替换发生了什么?为什么我不能像手动使用目录名称中的波浪号那样通过变量来 ls 目录?
答案1
当波形符是变量扩展结果的一部分时,shellbash
将不会扩展。~
不带引号的波形符前缀(~
,~+
或~username
对于当前用户名为username
)仅在位于单词开头或紧跟在=
或后面:
(可选地后跟/
和 其他路径元素)时扩展到当前用户的主目录。
在您的情况下,在分配给您的变量时进行扩展会更容易backupfolder
。如果您留下波形符,就会发生这种情况未引用的(既不使用单引号也不使用双引号):
backupfolder=~/db_backups
ls "$backupfolder"
...或者如果您$HOME
改为使用(不带单引号):
backupfolder=$HOME/db_backups
ls "$backupfolder"
在这两个赋值中,shell 会将赋值运算符右侧的值扩展为db_backups
当前用户主目录中调用的路径名。
一般来说,$HOME
在脚本中使用通常更容易,并将其留给~
交互式会话,它可以作为方便的快捷方式。该HOME
变量始终表现为多变的。
答案2
简而言之,您需要显式且不带引号的~user/
(或~/
),并且它不能是变量扩展的结果。
你需要backupfolder=~/'db_backups'
有一个成功的ls $backupfolder
长描述
波浪线扩展可能发生的唯一方法是拥有一个实际的未引用的 ~
最多也未引用的 /
,或字符串的结尾。
Anecho ~cris/'one space'
将扩展波浪号(和用户名),但如果没有实际的波浪号,~
则不会扩展波浪号。有趣的是,这样的命令需要引用,因为路径值中包含一个空格one space
。
此外,如果此列表中的任何扩展(在 bash 中的大括号扩展后扩展):波形符扩展、参数和变量扩展、算术扩展和命令替换被执行(以从左到右的方式完成),列表中的其他单词都不会被重新应用于同一个单词(所有都同时发生,有点)。
然后,大括号扩展(要发生的第一个扩展)可以通过列表进行额外扩展,并且(最后两个扩展)单词分割和路径名扩展将应用于前面步骤的结果。例如,这将扩展三个变量:
$ echo $HIST{FILE,FILESIZE,SIZE}
/home/cris/.bash_history 2000 1000
大括号扩展的结果通过变量扩展重新扩展。但是变量扩展不会被另一个扩展重新扩展:
$ b='$((2+2))'; echo $b
$((2+2))
简而言之,您需要显式且不带引号的~user/
(或~/
),并且它不能是变量扩展的结果。
请注意,算术展开不属于“仅一次展开”规则。在算术展开式中,展开式可能会递归几个步骤。例如:
$ a=b; b=c; c=d; d=23; echo $(($a))
23
请注意,我没有列出,process substitution
但也应该添加。