Bash 脚本 -e 不检测变量中的文件名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3129784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash script -e not detecting filename in a variable
提问by thornate
In a BASH script, I'm trying to detect whether a file exists. The filename is in a variable but the -e command seems to be unable to detect the file. The following code always outputs "~/misc/tasks/drupal_backup.sh does not exist"
在 BASH 脚本中,我试图检测文件是否存在。文件名在一个变量中,但 -e 命令似乎无法检测到该文件。以下代码总是输出“~/misc/tasks/drupal_backup.sh不存在”
filename="~/misc/tasks/drupal_backup.sh"
if [ -e "$filename" ]; then
echo "$filename exists"
else
echo "$filename does not exist"
fi
On the other hand, the following code detects the file correctly:
另一方面,以下代码正确检测文件:
if [ -e ~/misc/tasks/drupal_backup.sh ]; then
echo "$filename exists"
else
echo "$filename does not exist"
fi
Why would this be? How can I get it to detect the file when the filename is in a variable?
为什么会这样?当文件名在变量中时,如何让它检测文件?
回答by paxdiablo
That's an interesting one. Substituting $HOMEfor ~works as does removing the quotes from the assignment.
这是一个有趣的。代$HOME的~作品并除去转让的报价。
If you put a set -xat the top of that script, you'll see that the version with quotes sets filename to ~/...which is what's given to -e. If you remove the quotes, filename is set to the expanded /home/somebody/.... So in the first case, you see:
如果将 aset -x放在该脚本的顶部,您将看到带引号的版本将文件名设置~/...为-e. 如果删除引号,文件名将设置为扩展的/home/somebody/.... 所以在第一种情况下,你会看到:
+ [ -e ~/... ]
and it doesn't like it. In the second case, you see:
它不喜欢它。在第二种情况下,您会看到:
+ [ -e /home/somebody/... ]
and it doeswork.
它确实有效。
If you do it without the variable, you see:
如果您在没有变量的情况下执行此操作,您会看到:
+ [ -e /home/somebody/... ]
and, yes, it works.
是的,它有效。
After a bit of investigation, I've found that it's actually the order in which bashperforms its expansions. From the bash man page:
经过一番调查,我发现它实际上是bash执行扩展的顺序。从 bash 手册页:
The order of expansions is: brace expansion, tilde expansion, parameter, variable and arithmetic expansion and command substitution (done in a left-to-right fashion), word splitting, and pathname expansion.
扩展的顺序是:大括号扩展、波浪号扩展、参数、变量和算术扩展以及命令替换(以从左到右的方式完成)、分词和路径名扩展。
That's why it's not working, the variable is substituted afterthe tilde expansion. In other words, at the point where bashwants to expand ~, there isn't one. It's only after variable expansion does the word get changed into ~/...and there will be no tilde expansion after that.
这就是它不起作用的原因,变量在波浪号扩展后被替换。换句话说,在bash想要扩展的地方~,没有一个。只有在变量扩展之后才会将单词更改为~/...,之后不会有波浪号扩展。
One thing you coulddo is to change your ifstatement to:
您可以做的一件事是将您的if声明更改为:
if [[ -e $(eval echo $filename) ]]; then
This will evaluate the $filename argument twice. The first time (with eval), there will be no ~during the tilde expansion phase but $filenamewill be changed to ~/...during the variable expansion phase.
这将评估 $filename 参数两次。第一次(带eval),~在波浪号展开阶段$filename不会有,但~/...在可变展开阶段会改为。
Then, on the second evaluation (the one being done as part of the ifitself), the ~will be there during the tilde expansion phase.
然后,在第二次评估(作为if自身的一部分进行的评估)时,~将在波浪号扩展阶段出现。
I've tested that on my .profilefile and it seems to work, I suggest you confirm in your particular case.
我已经在我的.profile文件中测试过,它似乎有效,我建议你在你的特定情况下确认。

