What command checks if a directory exists or not within a Bash shell script?
35 Answers
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.
-
44If 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. Commented Jul 21, 2009 at 16:36 -
4For modern versions of bash, ksh, etc. [...] is a builtin– fpmurphyCommented Mar 24, 2011 at 14:22
-
99One 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 likeif [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi
; this will fail if"$DIRECTORY"
is a file. (Of course you should check whethermkdir
succeeded anyway; there are a number of reasons it can fail.) Commented Aug 9, 2011 at 23:46 -
11It 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.– AlfeCommented Sep 9, 2013 at 11:51
-
21Instead of testing for both the directory (
-d
) and the symlink (-L
), it's easier just to append a slash to the variable, likeif [ -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.– ghotiCommented Jan 17, 2017 at 9:21
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.
-
22Another reason to use double quotes is in case $DIRECTORY is not set for some reason. Commented Sep 15, 2008 at 22:41
-
6"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."– michaelCommented Sep 12, 2014 at 1:31
-
4Directories 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.– tvCaCommented Dec 24, 2014 at 13:57
-
33@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.)– JABCommented Aug 12, 2015 at 15:52
-
8Ha. Spaces are just characters that have no glyphs usually. Anyway, you can escape them with a backslash. Commented Oct 18, 2016 at 8:27
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.
-
15or, 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
– michaelCommented Sep 12, 2014 at 1:47
I find the double-bracket version of test
makes writing logic tests more natural:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
For the meaning of -L
and other conditional expressions, see Bash Reference Documentation: 6.4 Bash Conditional Expressions.
-
19@TheVillageIdiot and @Hedgehog, are you using bash shell? The double bracket isn't universally supported. Here's a SO answer on that point: stackoverflow.com/questions/669452/… Commented Jul 2, 2011 at 14:54
-
9And in Busybox ash with default compilation options
[[ ]]
is supported, but doesn't in fact provide any different functionality to[ ]
. If portability is a concern, stick with[ ]
and use the necessary workarounds. Commented May 31, 2012 at 15:34 -
9...if using bash constructs in a shell script, the first line of the script should be: #!/bin/bash (and not #!/bin/sh, ksh, etc)– michaelCommented Sep 12, 2014 at 1:23
-
5When using double square brackets in bash, you do not need to quote the variables.– Hugo GCommented Aug 11, 2017 at 5:58
-
1@AdamKatz Portability and deprecation of features in dash don't matter since this is about bash. Commented May 22, 2021 at 20:09
Shorter form:
# if $DIR is a directory, then print yes
[ -d "$DIR" ] && echo "Yes"
-
11Does this work like this:
if $dir is a dir, then echo "yes"
? A bit of explanation would help :)– MartijnCommented Aug 5, 2016 at 7:38 -
9
cmd && other
is a common shorthand forif cmd; then other; fi
-- this works with most programming languages which support Boolean logic, and is known as short-circuit evaluation.– tripleeeCommented Oct 5, 2016 at 4:03 -
8The behavior is not the same under
set -e
(which is a shell programming best practice).– dolmenCommented Jul 23, 2018 at 12:40 -
3@dolmen the
[ -d "$DIR" ]
is checked (followed by&& echo Yes
), so I believeset -e
makes no difference to the script behaviour (i.e if the test fails, the script continues normally).– tzotCommented Sep 4, 2018 at 16:03 -
@dolmen That's not correct. The behaviour is exactly the same under
set -e
. Except that if echo fails, the script will exit.[ -d "$DIR" ]
alone (no&& cmd ...
) will cause the script to exit underset -e
, if the test fails (ie. the directory does not exist, or$DIR
exists but is not a directory).– danCommented Jul 18, 2022 at 10:40
A simple script to test if a directory or file is present or not:
if [ -d /home/ram/dir ] # For file "if [ -f /home/rama/file ]" then echo "dir present" else echo "dir not present" fi
A simple script to check whether the directory is present or not:
mkdir tempdir # If you want to check file use touch instead of mkdir ret=$? if [ "$ret" == "0" ] then echo "dir present" else echo "dir not present" fi
The above scripts will check if the directory is present or not
$?
if the last command is a success it returns "0", else a non-zero value. Supposetempdir
is already present. Thenmkdir tempdir
will give an error like below:mkdir: cannot create directory ‘tempdir’: File exists
-
8The second one would create the directory, if it didn't exist at first. Then it's not idempotent. Commented Mar 6, 2019 at 6:47
-
2👆👆👆. The 2nd one seems dangerous. Since it creates the directory, it's not even true anymore that the dir is not present.– ChrisCommented Feb 7, 2020 at 21:38
-
mkdir will also not create the full path (without a param), but the opposite would be even more dangerous, as you are not even able to revert (rm -f) the changes as you don't know which directories it created– venimusCommented Mar 23, 2021 at 23:19
To check if a directory exists you can use a simple if
structure like this:
if [ -d directory/path to a directory ] ; then
# Things to do
else #if needed #also: elif [new condition]
# Things to do
fi
You can also do it in the negative:
if [ ! -d directory/path to a directory ] ; then
# Things to do when not an existing directory
Note: Be careful. Leave empty spaces on either side of both opening and closing braces.
With the same syntax you can use:
-e: any kind of archive
-f: file
-h: symbolic link
-r: readable file
-w: writable file
-x: executable file
-s: file size greater than zero
-
How is this any better than the accepted answer from 2008, aside from going off-topic with the file switches? Commented Mar 5, 2020 at 13:14
-
better, because of [ ! -d directory/path to a directory ] Commented Mar 27, 2020 at 19:46
You can use test -d
(see man test
).
-d file
True if file exists and is a directory.
For example:
test -d "/etc" && echo Exists || echo Does not exist
Note: The test
command is same as conditional expression [
(see: man [
), so it's portable across shell scripts.
[
- This is a synonym for thetest
builtin, but the last argument must, be a literal]
, to match the opening[
.
For possible options or further help, check:
help [
help test
man test
orman [
Or for something completely useless:
[ -d . ] || echo "No"
-
9It will never print "No". Current directory always exists, unless deleted by another thread or other ways.– JahidCommented Apr 19, 2015 at 0:49
Here's a very pragmatic idiom:
(cd $dir) || return # Is this a directory,
# and do we have access?
I typically wrap it in a function:
can_use_as_dir() {
(cd ${1:?pathname expected}) || return
}
Or:
assert_dir_access() {
(cd ${1:?pathname expected}) || exit
}
The nice thing about this approach is that I do not have to think of a good error message.
cd
will give me a standard one line message to standard error already. It will also give more information than I will be able to provide. By performing the cd
inside a subshell ( ... )
, the command does not affect the current directory of the caller. If the directory exists, this subshell and the function are just a no-op.
Next is the argument that we pass to cd
: ${1:?pathname expected}
. This is a more elaborate form of parameter substitution which is explained in more detail below.
Tl;dr: If the string passed into this function is empty, we again exit from the subshell ( ... )
and return from the function with the given error message.
Quoting from the ksh93
man page:
${parameter:?word}
If
parameter
is set and is non-null then substitute its value; otherwise, printword
and exit from the shell (if not interactive). Ifword
is omitted then a standard message is printed.
and
If the colon
:
is omitted from the above expressions, then the shell only checks whether parameter is set or not.
The phrasing here is peculiar to the shell documentation, as word
may refer to any reasonable string, including whitespace.
In this particular case, I know that the standard error message 1: parameter not set
is not sufficient, so I zoom in on the type of value that we expect here - the pathname
of a directory.
A philosophical note:
The shell is not an object oriented language, so the message says pathname
, not directory
. At this level, I'd rather keep it simple - the arguments to a function are just strings.
-
This do more than only check for existance: This check for accessibility at your user level. SO question stand for existance only. So right answer is
test -d
as @Grundlefleck explained. Commented Feb 9, 2013 at 20:16 -
8@F.Hauri - He didn't ask for anything more, that's true. However, I've found that I typically need to know more than that. Commented Feb 9, 2013 at 23:50
-
And it never occurred to me that no test can be conclusive, unless it runs as root.
test -d /unreadable/exists
will fail, even if the argument exists. Commented Apr 2, 2016 at 17:32
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
The above code checks if the directory exists and if it is writable.
-
1-a is identical in effect to -e. It has been "deprecated," and its use is discouraged. Commented Jan 28, 2014 at 8:39
More features using find
Check existence of the folder within sub-directories:
found=`find -type d -name "myDirectory"` if [ -n "$found" ] then # The variable 'found' contains the full path where "myDirectory" is. # It may contain several lines if there are several folders named "myDirectory". fi
Check existence of one or several folders based on a pattern within the current directory:
found=`find -maxdepth 1 -type d -name "my*"` if [ -n "$found" ] then # The variable 'found' contains the full path where folders "my*" have been found. fi
Both combinations. In the following example, it checks the existence of the folder in the current directory:
found=`find -maxdepth 1 -type d -name "myDirectory"` if [ -n "$found" ] then # The variable 'found' is not empty => "myDirectory"` exists. fi
-
Hi Niel. Your idea may be useful to check the existence of directories depending on a pattern like:
find -maxdepth 1 -type d -name 'pattern'
. Do you mind if I append in your answer this trick? Cheers ;)– oHoCommented Nov 18, 2013 at 13:54 -
love this. all the rest of these
-d
suggestions require that you can access that directory, but if we just need to check for existence, this find approach is great. Commented Jun 17, 2024 at 1:38
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
Actually, you should use several tools to get a bulletproof approach:
DIR_PATH=`readlink -f "${the_stuff_you_test}"` # Get rid of symlinks and get abs path
if [[ -d "${DIR_PATH}" ]] ; Then # Now you're testing
echo "It's a dir";
fi
There isn't any need to worry about spaces and special characters as long as you use "${}"
.
Note that [[]]
is not as portable as []
, but since most people work with modern versions of Bash (since after all, most people don't even work with command line :-p), the benefit is greater than the trouble.
Have you considered just doing whatever you want to do in the if
rather than looking before you leap?
I.e., if you want to check for the existence of a directory before you enter it, try just doing this:
if pushd /path/you/want/to/enter; then
# Commands you want to run in this directory
popd
fi
If the path you give to pushd
exists, you'll enter it and it'll exit with 0
, which means the then
portion of the statement will execute. If it doesn't exist, nothing will happen (other than some output saying the directory doesn't exist, which is probably a helpful side-effect anyways for debugging).
It seems better than this, which requires repeating yourself:
if [ -d /path/you/want/to/enter ]; then
pushd /path/you/want/to/enter
# Commands you want to run in this directory
popd
fi
The same thing works with cd
, mv
, rm
, etc... if you try them on files that don't exist, they'll exit with an error and print a message saying it doesn't exist, and your then
block will be skipped. If you try them on files that do exist, the command will execute and exit with a status of 0
, allowing your then
block to execute.
-
2pushd is to me the most elegant way of doing this. I was about to post it as an answer :)– melMassCommented Dec 7, 2017 at 17:10
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
N.B: Quoting variables is a good practice.
Explanation:
-d
: check if it's a directory-L
: check if it's a symbolic link
-
An explanation would be in order (by editing your answer, not here in comments). Commented May 7, 2020 at 12:14
-
Quoting variables (even with spaces with paths and metacharacters) is mostly not necessary if you're using Bash's
[[...]]
. The one exception is the RHS of=
, e.g.[[ $VAR = "$VAR" ]]
. (This is due to Bash interpreting the RHS as a glob.) Commented Jul 8, 2022 at 16:27
Check if the directory exists, else make one:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
-
21You could use
mkdir -p "$DIRECTORY"
for the same effect. Commented Jul 24, 2016 at 21:12 -
Need double quotes around
$DIRECTORY
in themkdir
part as well. Otherwise, word splitting may result in undesirable results. For example:dir="a b"; mkdir $dir
will result in two directoriesa
andb
being created, rather than a singlea b
directory. Commented Feb 22, 2021 at 3:55
[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
-
An explanation would be in order (by editing your answer, not here in comments). Commented May 7, 2020 at 12:07
To check more than one directory use this code:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
Using the -e
check will check for files and this includes directories.
if [ -e ${FILE_PATH_AND_NAME} ]
then
echo "The file or directory exists."
fi
This answer wrapped up as a shell script
Examples
$ is_dir ~
YES
$ is_dir /tmp
YES
$ is_dir ~/bin
YES
$ mkdir '/tmp/test me'
$ is_dir '/tmp/test me'
YES
$ is_dir /asdf/asdf
NO
# Example of calling it in another script
DIR=~/mydata
if [ $(is_dir $DIR) == "NO" ]
then
echo "Folder doesnt exist: $DIR";
exit;
fi
is_dir
function show_help()
{
IT=$(CAT <<EOF
usage: DIR
output: YES or NO, depending on whether or not the directory exists.
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ -z "$1" ]
then
show_help
fi
DIR=$1
if [ -d $DIR ]; then
echo "YES";
exit;
fi
echo "NO";
As per Jonathan's comment:
If you want to create the directory and it does not exist yet, then the simplest technique is to use mkdir -p
which creates the directory — and any missing directories up the path — and does not fail if the directory already exists, so you can do it all at once with:
mkdir -p /some/directory/you/want/to/exist || exit 1
One Liner:
[[ -d $Directory ]] && echo true
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists
fi
This is not completely true...
If you want to go to that directory, you also need to have the execute rights on the directory. Maybe you need to have write rights as well.
Therefore:
if [ -d "$DIRECTORY" ] && [ -x "$DIRECTORY" ] ; then
# ... to go to that directory (even if DIRECTORY is a link)
cd $DIRECTORY
pwd
fi
if [ -d "$DIRECTORY" ] && [ -w "$DIRECTORY" ] ; then
# ... to go to that directory and write something there (even if DIRECTORY is a link)
cd $DIRECTORY
touch foobar
fi
file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;
-
An explanation would be in order (by editing your answer, not here in comments). Commented May 7, 2020 at 12:07
The ls
command in conjunction with -l
(long listing) option returns attributes information about files and directories.
In particular the first character of ls -l
output it is usually a d
or a -
(dash). In case of a d
the one listed is a directory for sure.
The following command in just one line will tell you if the given ISDIR
variable contains a path to a directory or not:
[[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
Practical usage:
[claudio@nowhere ~]$ ISDIR="$HOME/Music"
[claudio@nowhere ~]$ ls -ld "$ISDIR"
drwxr-xr-x. 2 claudio claudio 4096 Aug 23 00:02 /home/claudio/Music
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
YES, /home/claudio/Music is a directory.
[claudio@nowhere ~]$ touch "empty file.txt"
[claudio@nowhere ~]$ ISDIR="$HOME/empty file.txt"
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directoy"
Sorry, /home/claudio/empty file.txt is not a directory
There are great solutions out there, but ultimately every script will fail if you're not in the right directory. So code like this:
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
will execute successfully only if at the moment of execution you're in a directory that has a subdirectory that you happen to check for.
I understand the initial question like this: to verify if a directory exists irrespective of the user's position in the file system. So using the command 'find' might do the trick:
dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d
This solution is good because it allows the use of wildcards, a useful feature when searching for files/directories. The only problem is that, if the searched directory doesn't exist, the 'find' command will print nothing to standard output (not an elegant solution for my taste) and will have nonetheless a zero exit. Maybe someone could improve on this.
-
13I'd be offended if a program went looking through my entire hard drive to find a directory rather than just politely looking in my current working directory or using the absolute path I give it. What you've suggested might be nice for a tool named
locate
but not nice for anything else...– sarnoldCommented Feb 1, 2012 at 9:29
If you want to check if a directory exists, regardless if it's a real directory or a symlink, use this:
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
Explanation: The "ls" command gives an error "ls: /x: No such file or directory" if the directory or symlink does not exist, and also sets the return code, which you can retrieve via "$?", to non-null (normally "1"). Be sure that you check the return code directly after calling "ls".
-
3Alternatively you can use this shorter version:
if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
– derFunkCommented Jan 8, 2014 at 10:51 -
ls
returning non-zero DOES NOT mean that the directory exists. The code should be:ls $DIR RETURN_CODE=$? if [ "$RETURN_CODE" != "0" ]; then echo "Cannot access directory $DIR (does not exist or no permission or something else altogether)!" exit $RETURN_CODE; fi echo "Directory $DIR already exists..."
– zerzevulCommented Feb 19, 2021 at 13:25