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
$HOMEfor~works as does removing the quotes from the assignment.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:and it doesn’t like it. In the second case, you see:
and it does work.
If you do it without the variable, you see:
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:That’s why it’s not working, the variable is substituted after the 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.One thing you could do is to change your
ifstatement to: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.Then, on the second evaluation (the one being done as part of the
ifitself), the~will be there during the tilde expansion phase.I’ve tested that on my
.profilefile and it seems to work, I suggest you confirm in your particular case.