Check if directory exists using home character (~) in bash fails

Solution 1:

Justin clarified his question in his first comment on quanta's answer. He is reading in a line of text using read (or by some other dynamic means) and wants to expand the tilde.

The question becomes "How do you perform tilde expansion on the contents of a variable?"

The general approach is to use eval, but it comes with some important caveats, namely spaces and output redirection (>) in the variable. The following seems to work for me:

read -p "Provide the destination directory: " DESTINATION

if [ ! -d "`eval echo ${DESTINATION//>}`" ]; then
    echo "'$DESTINATION' does not exist." >&2;
    exit 1;
fi

Try it with each of the following inputs:

~
~/existing_dir
~/existing dir with spaces
~/nonexistant_dir
~/nonexistant dir with spaces
~/string containing > redirection
~/string containing > redirection > again and >> again

Explanation

  • The ${mypath//>} strips out > characters which could clobber a file during the eval.
  • The eval echo ... is what does the actual tilde expansion
  • The double-quotes around the eval are for support of filenames with spaces.

As a supplement to this, you can improve the UX by adding the -e option to read:

read -p "Provide the destination directory: " -e DESTINATION

Now when the user types in tilde and hits tab, it will expand. This approach does not replace the eval approach above, however, as the expansion only happens if the user hits tab. If he just types in ~/foo and hits enter, it will remain as a tilde.

See also:

  • https://stackoverflow.com/questions/3963716/how-to-manually-expand-a-special-variable-ex-tilde-in-bash

Solution 2:

Remove the double quotes around the directory to see if it works:

if [ ! -d ~/Desktop ]; then
   echo "DOES NOT EXIST"
   exit 1;
fi

The reason for it is tilde expansion only works when it is unquoted.

info "(bash) Tilde Expansion"

3.5.2 Tilde Expansion
---------------------

If a word begins with an unquoted tilde character (`~'), all of the
characters up to the first unquoted slash (or all characters, if there
is no unquoted slash) are considered a TILDE-PREFIX.  If none of the
characters in the tilde-prefix are quoted, the characters in the
tilde-prefix following the tilde are treated as a possible LOGIN NAME.
If this login name is the null string, the tilde is replaced with the
value of the `HOME' shell variable.  If `HOME' is unset, the home
directory of the user executing the shell is substituted instead.
Otherwise, the tilde-prefix is replaced with the home directory
associated with the specified login name.

Solution 3:

It doesn't work not only on Mac but on any platform that runs bash on.

When you quote "~/Desktop" you are telling bash to look for Desktop inside the ~ folder. The quote removes the special purpose of ~

See -- http://www.gnu.org/software/bash/manual/bashref.html#Tilde-Expansion

Remove the double quotes and it should work.

Solution 4:

run

echo $HOME

use $HOME, and make sure the user is actually using the script. if root uses ~ its going to look in /root, not /home/$USER.

if [ ! -d "$HOME/Desktop" ]; then
   echo "DOES NOT EXIST"
   exit 1;
fi