17

Why does the following bash check if a directory fail?

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

~/Desktop does indeed exist. This is on a Mac by the way.


The problem is with this type of script

read -p "Provide the destination directory: " DESTINATION

if [ ! -d $DESTINATION ]; then
    echo "\t'$DESTINATION' does not exist." >&2;
    exit 1;
fi
1
  • 1
    Just like when you do cd "~/Desktop" you also get an error. It has to be unquoted or stored as a variable (without quotes). For example, a=~/Desktop; cd $a; works but not a="~/Desktop"; cd Desktop; See serverfault.com/questions/417252/…
    – dylnmc
    Nov 20, 2014 at 18:10

5 Answers 5

8

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:

26

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.
3
  • How about if the value comes in dynamically. I.e. (pastie.org/4471350) and DESTINATION is ~/Desktop.
    – Justin
    Aug 14, 2012 at 5:21
  • 3
    Tilde-expansion is done when the variable is set, not when it's evaluated, so that's not a fair example.
    – MadHatter
    Aug 14, 2012 at 5:34
  • +1, this is enough to solve my problem. Apr 5, 2016 at 8:00
4

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.

1

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
-1
if [ ! -d "$HOME/Desktop" ]; then
   echo "DOES NOT EXIST"
   exit 1;
fi

should be $HOME instead of ~

~ is a KEYBOARD thing

1
  • If you read the other answer here you would realize this is wrong.
    – chicks
    May 9, 2017 at 15:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .