How to Check if a File or Directory Exists in Bash

When writing shell scripts, you may find yourself in a situation where you need to perform an action based on whether a file exists or not.
In Bash, you can use the test command to check whether a file exists and determine the type of the file.
The test command takes one of the following syntax forms:
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]If you want your script to be portable, prefer the [ form, which is available in POSIX shells. The [[ (double bracket) form is supported by Bash, Zsh, and Ksh, but it is not part of POSIX sh.
Check if File Exists
When checking if a file exists, the most commonly used FILE operators are -e and -f. The first one will check whether a file exists regardless of the type, while the second one will return true only if the FILE is a regular file (not a directory or a device).
To check whether a path exists regardless of its type (file, directory, socket, and so on), use -e:
FILE=/etc/resolv.conf
if [ -e "$FILE" ]; then
echo "$FILE exists."
fiThe most readable option when checking whether a file exists or not is to use the test command in combination with the if statement
. Any of the snippets below will check whether the /etc/resolv.conf file exists:
FILE=/etc/resolv.conf
if test -f "$FILE"; then
echo "$FILE exists."
fiFILE=/etc/resolv.conf
if [ -f "$FILE" ]; then
echo "$FILE exists."
fiFILE=/etc/resolv.conf
if [[ -f "$FILE" ]]; then
echo "$FILE exists."
fiIf you want to perform a different action based on whether the file exists or not, use the if/then construct:
FILE=/etc/resolv.conf
if [ -f "$FILE" ]; then
echo "$FILE exists."
else
echo "$FILE does not exist."
fiYou can also use the test command without the if statement. The command after the && operator will only be executed if the exit status
of the test command is true.
FILE=/etc/resolv.conf
test -f "$FILE" && echo "$FILE exists."[ -f "$FILE" ] && echo "$FILE exists."[[ -f "$FILE" ]] && echo "$FILE exists."If you want to run a series of commands after the && operator, enclose the commands in curly brackets separated by ; or &&:
[ -f "$FILE" ] && { echo "$FILE exists."; cp "$FILE" /tmp/; }For a quick one-liner that only runs when the file exists, use &&:
[ -f "$FILE" ] && echo "$FILE exists."If you need one action when the file exists and another when it does not, use an if statement instead:
if [ -f "$FILE" ]; then
echo "$FILE exists."
else
echo "$FILE does not exist."
fiCheck if Directory Exists
The flag -d allows you to test whether a file is a directory or not.
For example, to check whether the /etc/docker directory exists, you would use:
FILE=/etc/docker
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi[ -d "$FILE" ] && echo "$FILE is a directory."To run different commands depending on whether the directory exists, use an if/else block:
FILE=/etc/docker
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
else
echo "$FILE does not exist or is not a directory."
fiTo check whether a directory does not exist, negate the expression with !:
FILE=/etc/docker
if [ ! -d "$FILE" ]; then
echo "$FILE does not exist."
fiCheck if File Does Not Exist
Like many other languages, the test expression can be negated using the ! (exclamation mark) logical not operator:
FILE=/etc/docker
if [ ! -f "$FILE" ]; then
echo "$FILE does not exist."
fiThe same check as a one-liner:
[ ! -f "$FILE" ] && echo "$FILE does not exist."Check if File Is Readable, Writable, or Executable
To test permissions, use -r, -w, and -x:
FILE=/usr/local/bin/script.sh
if [ -r "$FILE" ]; then
echo "$FILE is readable."
fiif [ -w "$FILE" ]; then
echo "$FILE is writable."
fiif [ -x "$FILE" ]; then
echo "$FILE is executable."
fiCheck if File Is Not Empty
Use -s to check for a file that exists and has nonzero size:
FILE=/var/log/syslog
if [ -s "$FILE" ]; then
echo "$FILE is not empty."
fiCheck if a File Is a Symlink
Use -L to check for a symbolic link:
FILE=/etc/localtime
if [ -L "$FILE" ]; then
echo "$FILE is a symbolic link."
fiCheck if Multiple Files Exist
To test whether multiple files exist, combine separate checks with &&:
if [ -f /etc/resolv.conf ] && [ -f /etc/hosts ]; then
echo "Both files exist."
fiif [[ -f /etc/resolv.conf && -f /etc/hosts ]]; then
echo "Both files exist."
fiEquivalent variants without using the IF statement:
[ -f /etc/resolv.conf ] && [ -f /etc/hosts ] && echo "Both files exist."[[ -f /etc/resolv.conf && -f /etc/hosts ]] && echo "Both files exist."File Test Operators
The test command includes the following FILE operators that allow you to test for particular types of files:
-bFILE- True if the FILE exists and is a special block file.-cFILE- True if the FILE exists and is a special character file.-dFILE- True if the FILE exists and is a directory.-eFILE- True if the FILE exists and is a file, regardless of type (node, directory, socket, etc.).-fFILE- True if the FILE exists and is a regular file (not a directory or device).-GFILE- True if the FILE exists and has the same group as the user running the command.-hFILE- True if the FILE exists and is a symbolic link.-gFILE- True if the FILE exists and has set-group-id (sgid) flag set.-kFILE- True if the FILE exists and has a sticky bit flag set.-LFILE- True if the FILE exists and is a symbolic link.-OFILE- True if the FILE exists and is owned by the user running the command.-pFILE- True if the FILE exists and is a pipe.-rFILE- True if the FILE exists and is readable.-SFILE- True if the FILE exists and is a socket.-sFILE- True if the FILE exists and has nonzero size.-uFILE- True if the FILE exists and set-user-id (suid) flag is set.-wFILE- True if the FILE exists and is writable.-xFILE- True if the FILE exists and is executable.
Conclusion
For scripts that run across different shells, the single-bracket [ form is the portable choice. Double brackets [[ add useful extras like pattern matching and regex but work only in Bash, Ksh, and Zsh. For the full operator reference, run man test or help test (for the built-in version) in your terminal.
Tags
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page