2010-06-28 73 views
5

在BASH脚本中,我试图检测文件是否存在。文件名在变量中,但-e命令似乎无法检测到该文件。下面的代码始终输出“〜/其它/任务/ drupal_backup.sh不存在”Bash脚本-e未检测到变量中的文件名

filename="~/misc/tasks/drupal_backup.sh" 

if [ -e "$filename" ]; then 
    echo "$filename exists" 
else 
    echo "$filename does not exist" 
fi 

在另一方面,下面的代码检测正确的文件:

if [ -e ~/misc/tasks/drupal_backup.sh ]; then 
    echo "$filename exists" 
else 
    echo "$filename does not exist" 
fi 

为什么会变成这样?当文件名位于变量中时,如何才能检测文件?

+1

我认为'〜'是一个不应该在脚本中使用的命令行便利。 – 2010-06-28 03:20:14

回答

7

这是一个有趣的。将$HOME替换为~的作用与删除作业中的引号一样有效。

如果您将set -x置于该脚本的顶部,则会看到带引号的版本将文件名设置为~/...,这是给-e的内容。如果删除引号,文件名将被设置为扩展/home/somebody/...。因此,在第一种情况下,您会看到:

+ [ -e ~/... ] 

并且它不喜欢它。在第二种情况下,您会看到:

+ [ -e /home/somebody/... ] 

,它确实工作。

如果你做到这一点没有变,你看:

+ [ -e /home/somebody/... ] 

,是的,它的工作原理。


有点调查后,我发现,它实际上是在bash执行其扩展的顺序。从bash手册页:

扩展的顺序是:括号扩展,代字符扩展,参数,变量和算术扩展和命令替换(按照从左到右的方式完成),单词分割和路径名扩张。

这就是为什么它不工作,变量替换代字号扩展。换句话说,在bash想要扩大~的地方,没有一个。只有在变量扩展之后,单词才会变成~/...,之后就不会有代字符扩展。

有一件事你可能是改变你的if声明:

if [[ -e $(eval echo $filename) ]]; then 

这两次评估$ filename参数。第一次(eval),在波浪扩展阶段期间不会有~,但$filename将在可变扩展阶段更改为~/...

然后,在第二次评估时(作为if本身的一部分完成的评估),~将在代字号扩展阶段出现。

我测试过我的.profile文件,它似乎工作,我建议您在您的具体情况确认。

+0

谢谢!用$ HOME替换〜完美无缺。 – thornate 2010-06-28 03:24:01

+1

应该指出,你不应该使用'eval'。 “〜〜”是交互模式的一个很好的缩写,但是应该在脚本中避免出现这个原因。很多初始化脚本包含诸如'[-r〜/ .profile] &&之类的东西。 〜/ .profile',我不知道这是否适用于主目录中包含空格的情况。最好使用$ HOME并引用所有变量:'filename =“$ HOME/misc/tasks/drupal_backup.sh”'。在这种情况下,引号不是必需的,但它不是有害的,只需引用所有内容就更容易了,除非您确切知道可以在哪里删除引号。 – Philipp 2010-06-28 05:57:06

+0

@Phillipp,如果你打算在一个精英团体中做一个像“你永远不应该使用eval”的总括性陈述,你可能想考虑将它与你的推理结合起来:-) – paxdiablo 2010-06-28 06:14:34