When writing shell scripts in Bash, you might encounter situations that’ll require you to make decisions based on whether or not a particular file or directory exists.
In this article, we’re going over a few ways how you can check for existing files and/or directories in Bash.
What is the test command?
You can use the test command to find whether a file exists and, if it does, that kind of file you’re dealing with. There are three ways you can use the test command.
test Expression
[ expression ]
[[ expression ]]
If you want portability in your script, we suggest using the single bracket test command as available on all POSIX shells. The new, upgraded version of the test command ([[) is supported on most modern systems using Bash, Zsh, Ksh and of course, the default shell.
Also read: Bash ‘if else’ statement examples
How to check existing files in Bash?
To check if a file exists, we’ll use the test command in conjunction and either the -e or -f flags. The -e flag checks whether a file exists regardless of the file type, and the -f flag returns true only if the file in question is a regular file and not a directory or device.
We’ll also be using the if-else statement to make our code more readable. Any of the following three snippets will be able to check if a file called index.html in the /etc/lampp/index.html directory exists or not.
FILE=/etc/lampp/index.html
if test -f "$FILE"; then
echo "$FILE exists."
fi
FILE=/etc/lampp/index.html
if [ -f "$FILE" ]; then
echo "$FILE exists."
fi
FILE=/etc/lampp/index.html
if [[ -f "$FILE" ]]; then
echo "$FILE exists."
fi
If you want to perform different actions based on whether a file exists or not, throw in an else statement in the aforementioned snippets.
FILE=/etc/lampp/index.html
if [ -f "$FILE" ]; then
echo "$FILE exists."
else
echo "$FILE does not exist."
fi
Always make sure to use double quotes when writing file names to avoid misparsing files with white spaces in them.
If you want, you can also use the test command without the if-else statements. Here’s how.
test -f /etc/lampp/index.html && echo "$FILE exists."
[ -f /etc/lampp/index.html ] && echo "$FILE exists."
[[ -f /etc/lampp/index.html ]] && echo "$FILE exists."
Note that in the above snippet, the command after the && logical operator will only execute if the test command’s exit status is true. If you’re looking to run a series of commands after the && operator, enclose the commands in curly brackets separated by either a semi-colon or &&.
[ -f /etc/lampp/index.html ] && { echo "$FILE exist."; cp "$FILE" /tmp/; }
You can also perform an action based on the fact that a file isn’t present. Substitute the && operator or the ||one. In this case, the command after the || will only execute if the test command’s exit status is false.
[ -f /etc/lampp/index.html ] && echo "$FILE exist." || echo "$FILE does not exist."
Also read: How to compare Strings in Bash?
How to check existing directories in Bash?
Similar to files, you can also check for directories using the test command. All you have to do is add the -d flag.
FILE=/etc/lampp/
if [ -d "$FILE" ]; then
echo "$FILE is a directory."
fi
Or in a single line.
[ -d /etc/lampp ] && echo "$FILE is a directory."
Consider using double brackets instead of single ones if you’ll only be running your script on modern Linux distros.
Also read: How to exit Bash script?
How to check if a file doesn’t exist?
Like every other programming language, you can negate any test condition using the logical not (!) operator.
FILE=/etc/lampp/index.html
if [ ! -f "$FILE" ]; then
echo "$FILE does not exist."
fi
Or in a single line, as follows.
[ ! -f /etc/lampp/index.html ] && echo "$FILE does not exist."
Also read: Bash While loop explained
How to check multiple files at once in Bash?
You might think you’ll need to create a complex if-elseif-else statement tree to check for multiple files, but that’s not necessarily the case.
You can use the -a flag or the logical operator with the double bracket test command to check for multiple files at once.
if [ -f /etc/lampp/index.html -a -f /etc/lampp/index.php ]; then
echo "Both files exist."
fi
Or using && along with the double bracket test command.
if [[ -f /etc/lampp/index.html && -f /etc/lampp/index.php ]]; then
echo "Both files exist."
fi
Without the if statements, the above snippets would look something like this, respectively.
[ -f /etc/lampp/index.html -a -f /etc/lampp/index.php ] && echo "Both files exist."
[[ -f /etc/lampp/index.html && -f /etc/lampp/index.php ]] && echo "Both files exist."
Also read: Bash functions explained
Common Bash test command flags
The test command has many useful flags that you can use to filter down your search for files. The most common ones are as follows.
- -b FILE: Returns true if the FILE exists and is a special block file.
- -c FILE: Returns true if the FILE exists and is a special character file.
- -d FILE: Returns true if the FILE exists and is a directory.
- -e FILE: Returns true if the FILE exists and is a file regardless of type.
- -f FILE: Returns true if the FILE exists and is a regular file.
- -G FILE: Returns true if the FILE exists and has the same group as the user running the command.
- -g FILE: Returns true if the FILE exists and the set-group-id (sguid) flag is set.
- -k FILE: Returns true if the FILE exists and is set to a sticky bit flag.
- -L FILE: Returns true if the FILE exists and is a symbolic link (symlink).
- -O FILE: Returns true if the FILE exists and is owned by the user running the command.
- -p FILE: Returns true if the FILE exists and is a pipe.
- -r FILE: Returns true if the FILE exists and is a readable file.
- -S FILE: Returns true if the FILE exists and is a socket.
- -s FILE: Returns true if the FILE exists and has a non-zero file size.
- -u FILE: Returns true if the FILE exists and the set-user-id (suid) flag is set.
- -w FILE: Returns true if the FILE exists and is a writable file.
- -x FILE: Returns true if the FILE exists and is an executable file.
Also read: How to create Bash aliases?