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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 22:15:56  来源:igfitidea点击:

Bash script -e not detecting filename in a variable

linuxbashshellfilenames

提问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文件中测试过,它似乎有效,我建议你在你的特定情况下确认。