简体   繁体   中英

Bash script -e not detecting filename in a variable

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"

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?

That's an interesting one. Substituting $HOME for ~ works as does removing the quotes from the assignment.

If you put a set -x at 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:

+ [ -e ~/... ]

and it doesn't like it. In the second case, you see:

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

and it does work.

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 bash performs its expansions. From the bash man page:

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 after the tilde expansion. In other words, at the point where bash wants 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.

One thing you could do is to change your if statement to:

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 $filename will be changed to ~/... during the variable expansion phase.

Then, on the second evaluation (the one being done as part of the if itself), the ~ will be there during the tilde expansion phase.

I've tested that on my .profile file and it seems to work, I suggest you confirm in your particular case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM