- How to Verify if a File or Directory Exists in Bash
- Introduction to the Test Command in Bash
- Verifying if a File Exists in Bash
- Checking if a Directory Exists in Bash
- Checking if a File Does Not Exist
- Checking if Multiple Files Exist
- File Test Operators
- Best Practices for Checking File or Directory Existence in Bash
- 1. Always Quote Your Variables
- 2. Use -e for General Existence Check
- 3. Prefer [[ Over [ or test
- 4. Check for Non-existence
- 5. Use Logical Operators for Multiple Conditions
- 6. Handle Errors Gracefully
- 7. Keep It Simple and Readable
- Conclusion
- How to check if a file exists in a shell script
- 7 Answers 7
How to Verify if a File or Directory Exists in Bash
When working with Bash scripts, it’s a common requirement to check if a file or directory exists before performing an operation. This guide will provide you with a comprehensive understanding of how to perform these checks in Bash, focusing on the test command and its various forms.
Introduction to the Test Command in Bash
The test command is a built-in function in Bash that evaluates conditional expressions. It’s a fundamental tool for checking file types and comparing values. The test command can be written in three syntax forms:
For scripts that need to be portable across different shells, it’s recommended to use the traditional test or [ command, which is available on all POSIX shells. The modern version of the test command, [[ (double brackets), is supported on most contemporary systems using Bash, Zsh, and Ksh as default shells.
Verifying if a File Exists in Bash
When you need to confirm if a file exists, Bash provides the -e and -f FILE operators. The -e operator checks if a file exists, regardless of its type, while -f returns true only if the file is a regular file (not a directory or a device).
Here’s an example of how you can use the test command with an if statement to check if a file exists:
FILE=/path/to/your/file if test -f "$FILE"; then echo "$FILE exists." fi
You can also use the [ or [[ forms:
FILE=/path/to/your/file if [ -f "$FILE" ]; then echo "$FILE exists." fi FILE=/path/to/your/file if [[ -f "$FILE" ]]; then echo "$FILE exists." fi
To perform different actions based on whether the file exists or not, use the if/then construct:
FILE=/path/to/your/file if [ -f "$FILE" ]; then echo "$FILE exists." else echo "$FILE does not exist." fi
Always use double quotes to avoid issues when dealing with files containing whitespace in their names.
You 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:
test -f /path/to/your/file && echo "$FILE exists." [ -f /path/to/your/file ] && echo "$FILE exists." [[ -f /path/to/your/file ]] && echo "$FILE exists."
Opposite to && , the statement after the || operator will only be executed if the exit status of the test command is false:
[ -f /path/to/your/file ] && echo "$FILE exist." || echo "$FILE does not exist."
Checking if a Directory Exists in Bash
The -d operator 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:
DIR=/path/to/your/directory if [ -d "$DIR" ]; then echo "$DIR is a directory." fi [ -d /path/to/your/directory ] && echo "$DIR is a directory."
You can also use the double brackets [[ instead of a single one [ .
Checking if a File Does Not Exist
Similar to many other languages, the test expression can be negated using the ! (exclamation mark) logical not operator:
FILE=/path/to/your/file if [ ! -f "$FILE" ]; then echo "$FILE does not exist." fi [ ! -f /path/to/your/file ] && echo "$FILE does not exist."
Checking if Multiple Files Exist
Instead of using complicated nested if/else constructs, you can use -a (or && with [[ ) to test if multiple files exist:
if [ -f /path/to/your/file1 -a -f /path/to/your/file2 ]; then echo "Both files exist." fi if [[ -f /path/to/your/file1 && -f /path/to/your/file2 ]]; then echo "Both files exist." fi
Equivalent variants without using the IF statement:
[ -f /path/to/your/file1 -a -f /path/to/your/file2 ] && echo "Both files exist." [[ -f /path/to/your/file1 && -f /path/to/your/file2 ]] && 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:
- -b FILE – True if the FILE exists and is a special block file.
- -c FILE – True if the FILE exists and is a special character file.
- -d FILE – True if the FILE exists and is a directory.
- -e FILE – True if the FILE exists and is a file, regardless of type (node, directory, socket, etc.).
- -f FILE – True if the FILE exists and is a regular file (not a directory or device).
- -G FILE – True if the FILE exists and has the same group as the user running the command.
- -h FILE – True if the FILE exists and is a symbolic link.
- -g FILE – True if the FILE exists and has set-group-id (sgid) flag set.
- -k FILE – True if the FILE exists and has a sticky bit flag set.
- -L FILE – True if the FILE exists and is a symbolic link.
- -O FILE – True if the FILE exists and is owned by the user running the command.
- -p FILE – True if the FILE exists and is a pipe.
- -r FILE – True if the FILE exists and is readable.
- -S FILE – True if the FILE exists and is a socket.
- -s FILE – True if the FILE exists and has nonzero size.
- -u FILE – True if the FILE exists, and set-user-id (suid) flag is set.
- -w FILE – True if the FILE exists and is writable.
- -x FILE – True if the FILE exists and is executable.
Best Practices for Checking File or Directory Existence in Bash
When writing Bash scripts that involve checking the existence of files or directories, it’s important to follow some best practices to ensure your scripts are robust, reliable, and easy to maintain.
1. Always Quote Your Variables
When dealing with filenames, always enclose your variables in double quotes. This prevents issues with filenames that contain spaces or special characters. For example:
FILE="/path/with spaces/file.txt" if [ -f "$FILE" ]; then echo "$FILE exists." fi
2. Use -e for General Existence Check
If you just need to check whether a file or directory exists, regardless of its type, use the -e operator. This can simplify your code and make it more readable.
3. Prefer [[ Over [ or test
The [[ command is a more modern and powerful version of [ and test . It supports more operators and is less prone to scripting errors. For example, it doesn’t word-split variable expansions.
4. Check for Non-existence
Sometimes, it’s more efficient to check for non-existence of a file or directory. For example, before creating a directory, check if it doesn’t already exist:
DIR="/path/to/dir" if [ ! -d "$DIR" ]; then mkdir "$DIR" fi
5. Use Logical Operators for Multiple Conditions
If you need to check multiple conditions, use logical operators like -a (AND) and -o (OR). This can make your code cleaner and easier to understand.
6. Handle Errors Gracefully
If a file or directory doesn’t exist, make sure your script handles this gracefully. Don’t assume that a file or directory will always exist.
7. Keep It Simple and Readable
Lastly, always aim for simplicity and readability in your scripts. Use clear variable names, add comments to explain what your code does, and organize your code in a logical way. This will make your scripts easier to maintain and debug.
Conclusion
This guide has provided a comprehensive overview of how to check if a file or directory exists in Bash. By understanding and utilizing the test command and its various forms, you can create more robust and reliable Bash scripts. Remember, practice is key when it comes to mastering these concepts, so don’t hesitate to try out these examples on your own.
How to check if a file exists in a shell script
I’d like to write a shell script which checks if a certain file, archived_sensor_data.json , exists, and if so, deletes it. Following http://www.cyberciti.biz/tips/find-out-if-file-exists-with-conditional-expressions.html, I’ve tried the following:
[-e archived_sensor_data.json] && rm archived_sensor_data.json
when I try to run the resulting test_controller script using the ./test_controller command. What is wrong with the code?
You must set one or more whitespace between opening square bracket «[» and option «-e» same as between filename and closing square bracket «]»
7 Answers 7
You’re missing a required space between the bracket and -e :
#!/bin/bash if [ -e x.txt ] then echo "ok" else echo "nok" fi
I finally added two blank spaces, one after the opening square bracket and one before the closing one: [ -e archived_sensor_data.json ] && rm archived_sensor_data.json . The script seems to work now.
The main difference here is the fact that you are using «bash» scripting instead of «shell» scripting. Notice that the first line that you have added was #!/bin/bash, so you are telling the machine to use «bash» instead of sh. Because sh doesn’t recognize that argument «-e»
Here is an alternative method using ls :
(ls x.txt && echo yes) || echo no
If you want to hide any output from ls so you only see yes or no, redirect stdout and stderr to /dev/null :
(ls x.txt >> /dev/null 2>&1 && echo yes) || echo no
This code means: «if ls is successful, there is such file, otherwise, there is none». If ls failed, it does not mean that file is missing. It might be some other error. For example, create file in directory owned by root and try to do ls under regular user. It will fail with Permission denied , which is not equivalent that file does not exist.
The backdrop to my solution recommendation is the story of a friend who, well into the second week of his first job, wiped half a build-server clean. So the basic task is to figure out if a file exists, and if so, let’s delete it. But there are a few treacherous rapids on this river:
- Everything is a file.
- Scripts have real power only if they solve general tasks
- To be general, we use variables
- We often use -f force in scripts to avoid manual intervention
- And also love -r recursive to make sure we create, copy and destroy in a timely fashion.
Consider the following scenario:
We have the file we want to delete: filesexists.json
This filename is stored in a variable
:~/Documents/thisfolderexists filevariable="filesexists.json"
We also hava a path variable to make things really flexible
:~/Documents/thisfolderexists pathtofile=".." :~/Documents/thisfolderexists ls $pathtofile filesexists.json history20170728 SE-Data-API.pem thisfolderexists
So let’s see if -e does what it is supposed to. Does the files exist?
:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $? 0
However, what would happen, if the file variable got accidentally be evaluated to nuffin’
:~/Documents/thisfolderexists filevariable="" :~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $? 0
What? It is supposed to return with an error. And this is the beginning of the story how that entire folder got deleted by accident
An alternative could be to test specifically for what we understand to be a ‘file’
:~/Documents/thisfolderexists filevariable="filesexists.json" :~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $? 0
:~/Documents/thisfolderexists filevariable="" :~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $? 1
So this is not a file and maybe, we do not want to delete that entire directory
man test has the following to say:
-b FILE FILE exists and is block special -c FILE FILE exists and is character special -d FILE FILE exists and is a directory -e FILE FILE exists -f FILE FILE exists and is a regular file . -h FILE FILE exists and is a symbolic link (same as -L)