Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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
share|improve this question
    
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 2 days ago

4 Answers 4

up vote 4 down vote accepted

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:

share|improve this answer

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.
share|improve this answer
    
How about if the value comes in dynamically. I.e. (pastie.org/4471350) and DESTINATION is ~/Desktop. –  Justin Aug 14 '12 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 '12 at 5:34
    
+1 for simplicity. –  math Aug 24 '12 at 6:33

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.

share|improve this answer

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.