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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With