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

Learn how do i check if a directory exists or not in a bash shell script? with practical examples, diagrams, and best practices. Covers bash, shell, unix development techniques with visual explanat...

How to Check if a Directory Exists in Bash Shell Scripts

Hero image for How do I check if a directory exists or not in a Bash shell script?

Learn various robust methods to verify the existence of a directory in Bash shell scripts, ensuring your scripts handle file system interactions gracefully and prevent errors.

When writing Bash shell scripts, it's a common requirement to check if a specific directory exists before performing operations like creating files within it, navigating into it, or deleting its contents. Failing to do so can lead to script errors, unexpected behavior, or even data loss. This article will guide you through the most reliable and idiomatic ways to check for directory existence in Bash, along with best practices.

Using the test Command ([ ])

The test command, often used in its shorthand form [ ], is the most fundamental way to perform conditional checks in Bash. It provides several operators for testing file attributes, including directory existence. The -d operator specifically checks if a given path refers to an existing directory.

# Basic check for directory existence
DIR_PATH="/path/to/my/directory"

if [ -d "$DIR_PATH" ]; then
  echo "Directory '$DIR_PATH' exists."
else
  echo "Directory '$DIR_PATH' does not exist."
fi

# Example with creating if not exists
NEW_DIR="/tmp/my_new_dir"

if [ ! -d "$NEW_DIR" ]; then
  echo "Directory '$NEW_DIR' does not exist. Creating it..."
  mkdir -p "$NEW_DIR"
  if [ $? -eq 0 ]; then
    echo "Directory '$NEW_DIR' created successfully."
  else
    echo "Failed to create directory '$NEW_DIR'."
  fi
else
  echo "Directory '$NEW_DIR' already exists."
fi

Basic usage of [ -d ] to check and conditionally create a directory.

Using the [[ ]] Compound Command

The [[ ]] compound command is an enhanced version of [ ] available in Bash (and other modern shells like Zsh and Ksh). It offers more advanced features, such as pattern matching and improved handling of word splitting, making it generally safer and more flexible for conditional expressions. It also supports the -d operator for directory checks.

# Using [[ -d ]] for directory existence check
TARGET_DIR="/var/log/nginx"

if [[ -d "$TARGET_DIR" ]]; then
  echo "Directory '$TARGET_DIR' exists and is a directory."
else
  echo "'$TARGET_DIR' is not an existing directory."
fi

# Combining with other checks (e.g., readability)
ANOTHER_DIR="/etc/passwd.d" # This might not exist or be a directory

if [[ -d "$ANOTHER_DIR" && -r "$ANOTHER_DIR" ]]; then
  echo "Directory '$ANOTHER_DIR' exists and is readable."
else
  echo "Directory '$ANOTHER_DIR' either doesn't exist, isn't a directory, or isn't readable."
fi

Checking directory existence with [[ -d ]] and combining conditions.

flowchart TD
    A[Start Script] --> B{Directory Path Provided?}
    B -- No --> C[Error: Path Missing]
    B -- Yes --> D{Check if Path Exists and is Directory?}
    D -- Yes (Exists) --> E[Perform Directory Operations]
    D -- No (Does Not Exist) --> F{Should Directory Be Created?}
    F -- Yes --> G[Create Directory]
    G --> E
    F -- No --> H[Exit or Handle Error]
    E --> I[End Script]
    C --> I
    H --> I

Decision flow for checking and handling directory existence in a script.

Alternative: Using find for More Complex Scenarios

While [ -d ] and [[ -d ]] are perfect for simple checks, sometimes you might need to find a directory with specific attributes or within a larger search scope. The find command is powerful for such scenarios, though it's generally overkill for a simple existence check.

# Check if a directory named 'logs' exists directly under /var
if find /var -maxdepth 1 -type d -name "logs" -print -quit | grep -q .; then
  echo "Directory 'logs' found under /var."
else
  echo "Directory 'logs' not found under /var."
fi

# More direct check using find and its exit status
# This is less efficient than [ -d ] for a single path
DIR_TO_CHECK="/opt/app/data"
if find "$DIR_TO_CHECK" -maxdepth 0 -type d > /dev/null 2>&1; then
  echo "'$DIR_TO_CHECK' exists and is a directory (using find)."
else
  echo "'$DIR_TO_CHECK' does not exist or is not a directory (using find)."
fi

Using find for directory existence, suitable for more complex searches.

Best Practices and Considerations

When checking for directory existence, keep the following best practices in mind to write robust and maintainable scripts:

1. Prioritize [[ -d ]] for Modern Bash

For scripts intended for Bash 3.x and newer, [[ -d ]] is generally preferred over [ -d ] due to its enhanced features and safer handling of variables and special characters. It's more forgiving and less prone to subtle errors.

2. Always Quote Variables

As mentioned, always enclose your directory path variables in double quotes (e.g., "$MY_DIR") within conditional expressions. This prevents word splitting and globbing issues, especially if paths contain spaces or wildcards.

3. Handle Non-Existence Gracefully

Decide how your script should behave if a directory doesn't exist. Should it create the directory (mkdir -p)? Should it exit with an error? Or should it simply skip an operation? Plan for these scenarios to prevent script failures.

4. Check Permissions if Necessary

Existence doesn't imply usability. If your script needs to write to a directory, you might also want to check for write permissions using -w (e.g., [[ -d "$DIR" && -w "$DIR" ]]).

5. Use mkdir -p for Creation

When creating directories, mkdir -p is invaluable as it creates parent directories as needed and does not throw an error if the directory already exists, simplifying your logic.