Categories
bash posix shell unix

How do I check if a directory exists in a Bash shell script?

4182

What command checks if a directory exists or not within a Bash shell script?

0

    5633

    To check if a directory exists:

    if [ -d "$DIRECTORY" ]; then
      echo "$DIRECTORY does exist."
    fi
    

    To check if a directory does not exist:

    if [ ! -d "$DIRECTORY" ]; then
      echo "$DIRECTORY does not exist."
    fi
    

    However, as Jon Ericson points out, subsequent commands may not work as intended if you do not take into account that a symbolic link to a directory will also pass this check.
    E.g. running this:

    ln -s "$ACTUAL_DIR" "$SYMLINK"
    if [ -d "$SYMLINK" ]; then 
      rmdir "$SYMLINK" 
    fi
    

    Will produce the error message:

    rmdir: failed to remove `symlink': Not a directory
    

    So symbolic links may have to be treated differently, if subsequent commands expect directories:

    if [ -d "$LINK_OR_DIR" ]; then 
      if [ -L "$LINK_OR_DIR" ]; then
        # It is a symlink!
        # Symbolic link specific commands go here.
        rm "$LINK_OR_DIR"
      else
        # It's a directory!
        # Directory command goes here.
        rmdir "$LINK_OR_DIR"
      fi
    fi
    

    Take particular note of the double-quotes used to wrap the variables. The reason for this is explained by 8jean in another answer.

    If the variables contain spaces or other unusual characters it will probably cause the script to fail.

    14

    • 36

      If you want to play it safe with the GNU tools, use of -- is highly recommended (end-of-options marker). Otherwise, if your variable contains something that looks like an option, the script’ll fail just as with spaces.

      Jul 21, 2009 at 16:36

    • 3

      For modern versions of bash, ksh, etc. […] is a builtin

      – fpmurphy

      Mar 24, 2011 at 14:22

    • 92

      One thing to keep in mind: [ ! -d "$DIRECTORY" ] will be true either if $DIRECTORY doesn’t exist, or if does exist but isn’t a directory. Consider something like if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi; this will fail if "$DIRECTORY" is a file. (Of course you should check whether mkdir succeeded anyway; there are a number of reasons it can fail.)

      Aug 9, 2011 at 23:46


    • 8

      It might be worth mentioning that as soon as the check has been performed the situation can have changed already due to other processes. In many cases it is better to just create or use the directory and react on a failure.

      – Alfe

      Sep 9, 2013 at 11:51

    • 16

      Instead of testing for both the directory (-d) and the symlink (-L), it’s easier just to append a slash to the variable, like if [ -d "${THING:+$THING/}" ]. A directory won’t mind the extra slash. A file will evaluate to false. Empty will remain empty, so false. And a symlink will be resolved to its destination. Of course, it depends on your goal. If you want to go there, this is fine. If you want to delete it, then the code in this answer is better.

      – ghoti

      Jan 17, 2017 at 9:21

    590

    Always wrap variables in double quotes when referencing them in a Bash script.

    if [ -d "$DIRECTORY" ]; then
        # Will enter here if $DIRECTORY exists, even if it contains spaces
    fi
    

    Kids these days put spaces and lots of other funny characters in their directory names. (Spaces! Back in my day, we didn’t have no fancy spaces!)
    One day, one of those kids will run your script with $DIRECTORY set to "My M0viez" and your script will blow up. You don’t want that. So use double quotes.

    13

    • 14

      Another reason to use double quotes is in case $DIRECTORY is not set for some reason.

      Sep 15, 2008 at 22:41

    • 3

      “always wrap variables in double quotes…in a bash script.” For bash, not technically necessary when using [[…]]; see tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS (note: no word splitting): “No filename expansion or word splitting takes place between [[ and ]], but there is parameter expansion and command substitution.”

      – michael

      Sep 12, 2014 at 1:31

    • 3

      Directories on Unix/Linux should not have any whitespaces, and subsequently scripts should not be adapted to it. It’s bad enough Windows supports it, with all consequences to Windows scripting, but please, for the love of whatever, no need to introduce unnecessary requirements.

      – tvCa

      Dec 24, 2014 at 13:57


    • 25

      @tvCa I find that users generally prefer to be allowed more flexibility in their directory names rather than being forced to make things easier for developers. (In fact, when dealing with long file names, I find ones without spaces to be a pain as that kills word wrapping even though I myself have suffered in the past from not accounting for paths with spaces in scripts and programs.)

      – JAB

      Aug 12, 2015 at 15:52


    • 3

      Ha. Spaces are just characters that have no glyphs usually. Anyway, you can escape them with a backslash.

      – uchuugaka

      Oct 18, 2016 at 8:27

    256

    Note the -d test can produce some surprising results:

    $ ln -s tmp/ t
    $ if [ -d t ]; then rmdir t; fi
    rmdir: directory "t": Path component not a directory
    

    File under: “When is a directory not a directory?” The answer: “When it’s a symlink to a directory.” A slightly more thorough test:

    if [ -d t ]; then 
       if [ -L t ]; then 
          rm t
       else 
          rmdir t
       fi
    fi
    

    You can find more information in the Bash manual on Bash conditional expressions and the [ builtin command and the [[ compound commmand.

    1

    • 13

      or, assuming it is only necessary to work on directories (and links can be ignored) => if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi … or, for one command that works on both links & dirs: rm -r tmpdir

      – michael

      Sep 12, 2014 at 1:47