Skip to content

10. Bash File Testing

Overview

Bash provides several conditional operators that can be used to check the characteristics and properties of files, directories, and special filesystem objects.

These tests are commonly used with if, while, and other conditional statements.

File Test Operators

Operator Description
-b Checks if the file is a block special file
-c Checks if the file is a character special file
-d Checks if the path is a directory
-e Checks if the path exists
-f Checks if the path is a regular file
-G Checks if the file is owned by the effective group ID
-g Checks if the set-group-ID bit is set
-k Checks if the sticky bit is set
-L Checks if the path is a symbolic link
-O Checks if the file is owned by the effective user ID
-r Checks if the file is readable
-S Checks if the file is a socket
-s Checks if the file exists and has a non-zero size
-u Checks if the set-user-ID bit is set
-w Checks if the file is writable
-x Checks if the file is executable

Checking if a File Exists

The -e operator can be used to determine whether a file or path exists.

#!/bin/bash

file="./file"

if [ -e "$file" ]; then
    echo "File exists"
else
    echo "File does not exist"
fi

If the file does not exist:

$ ./filetesting.sh
File does not exist

Create the file:

touch file

Run the script again:

$ ./filetesting.sh
File exists

Here, -e returns true when the specified path exists.

Using quotes around variables such as "$file" is recommended because it prevents problems when the filename contains spaces or special characters.

Checking for a Regular File

The -f operator checks whether a path exists and is a regular file.

#!/bin/bash

file="./file"

if [ -f "$file" ]; then
    echo "Regular file exists"
else
    echo "Not a regular file"
fi

This is different from -e. For example, a directory can satisfy -e, but it will not satisfy -f.

Checking for a Directory

Use -d to determine whether a directory exists.

#!/bin/bash

directory="./backup"

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

Create the directory and test again:

mkdir backup
./directorytesting.sh

Output:

Directory exists

Checking File Permissions

File tests can also be used to check permissions.

Readable

if [ -r "$file" ]; then
    echo "File is readable"
fi

Writable

if [ -w "$file" ]; then
    echo "File is writable"
fi

Executable

if [ -x "$file" ]; then
    echo "File is executable"
fi

These tests are useful when a script needs to verify permissions before attempting an operation.

Checking File Size

The -s operator checks whether a file exists and has a size greater than zero.

#!/bin/bash

file="./data.txt"

if [ -s "$file" ]; then
    echo "File contains data"
else
    echo "File is empty or does not exist"
fi

This can be useful when a script needs to determine whether a generated file actually contains data.

The -L operator checks whether a path is a symbolic link.

#!/bin/bash

file="./latest"

if [ -L "$file" ]; then
    echo "Symbolic link"
else
    echo "Not a symbolic link"
fi

For example:

ln -s /var/log/syslog latest

The test will then identify latest as a symbolic link.

Waiting Until a File Exists

File tests can also be combined with a while loop.

The following script waits until myfile is created:

#!/bin/bash

while [ ! -e "myfile" ]; do
    sleep 1
done

echo "myfile exists"

The ! operator negates the condition.

Without !:

[ -e "myfile" ]

means:

myfile exists

With !:

[ ! -e "myfile" ]

means:

myfile does not exist

Therefore, the loop continues while the file does not exist.

In another terminal, create the file:

touch myfile

The loop detects the file and exits:

myfile exists

The sleep 1 prevents the script from continuously checking the filesystem without a delay.

Combining File Tests

Multiple conditions can be combined to perform more specific checks.

#!/bin/bash

file="./script.sh"

if [ -f "$file" ] && [ -x "$file" ]; then
    echo "Regular executable file"
else
    echo "File is missing or not executable"
fi

Here:

-f "$file"

checks that the path is a regular file, while:

-x "$file"

checks that it is executable.

The && operator requires both conditions to be true.

Quick Examples

# Exists
[ -e "$file" ]

# Regular file
[ -f "$file" ]

# Directory
[ -d "$file" ]

# Readable
[ -r "$file" ]

# Writable
[ -w "$file" ]

# Executable
[ -x "$file" ]

# Non-empty
[ -s "$file" ]

# Symbolic link
[ -L "$file" ]

Key Concept

Bash file tests provide a simple way to make scripts aware of the filesystem. They can be used to verify that files or directories exist, check permissions, determine file types, and wait for files to appear.

A common pattern is:

if [ -f "$file" ]; then
    # File exists
fi

while a negated test can be used for waiting:

while [ ! -e "$file" ]; do
    sleep 1
done

These operators are fundamental when writing Bash scripts that interact with files, directories, logs, configuration files, temporary files, and other filesystem resources.