Web Analytics

File Test Operators

Beginner ~20 min read

File test operators are essential for any script that works with files and directories. They let you check if files exist, verify permissions, determine file types, and compare files. These operators are used constantly in real-world shell scripts for validation and conditional logic!

Existence and Permission Tests

The most common file tests check whether files exist and what permissions they have. These are the foundation of defensive scripting!

Output
Click Run to execute your code

Existence Operators

Operator Description Example
-e File exists (any type) [[ -e "$file" ]]
-f Exists and is a regular file [[ -f "$file" ]]
-d Exists and is a directory [[ -d "$dir" ]]
-L or -h Exists and is a symbolic link [[ -L "$link" ]]

Permission Operators

Operator Description Example
-r File is readable [[ -r "$file" ]]
-w File is writable [[ -w "$file" ]]
-x File is executable [[ -x "$script" ]]
-s File exists and size > 0 [[ -s "$file" ]]
Best Practice: Always check if a file exists before trying to read or modify it. Use [[ -f "$file" ]] && cat "$file" to avoid errors when the file doesn't exist.

File Type Tests

Beyond regular files and directories, Unix has several special file types. These operators help you identify them.

Output
Click Run to execute your code
Operator Description Common Examples
-f Regular file Scripts, text files, configs
-d Directory /home, /tmp, /var
-L Symbolic link /usr/bin/python -> python3
-b Block device /dev/sda, /dev/nvme0n1
-c Character device /dev/null, /dev/tty
-p Named pipe (FIFO) Inter-process communication
-S Socket /var/run/docker.sock
Pro Tip: The -f operator follows symbolic links. To check if something is a symlink regardless of what it points to, use -L. To check if a symlink points to a valid target, combine them: [[ -L "$link" && -e "$link" ]].

File Comparison Operators

These operators compare files by modification time and identity (same inode). Perfect for backup scripts and synchronization!

Output
Click Run to execute your code
Operator Description Use Case
file1 -nt file2 file1 is newer than file2 Backup/sync decisions
file1 -ot file2 file1 is older than file2 Cache invalidation
file1 -ef file2 Same file (same device & inode) Hard link detection
Caution: The -nt and -ot operators return false if either file doesn't exist. Always check existence first with -e if you're not sure the files exist!

String Length Tests

While not strictly file operators, -z and -n are often used alongside file tests to check variable values.

# -z: String is zero length (empty)
filename=""
if [[ -z "$filename" ]]; then
    echo "No filename provided"
fi

# -n: String is non-zero length (not empty)
filename="script.sh"
if [[ -n "$filename" ]]; then
    echo "Filename: $filename"
fi

# Common pattern: validate before using
if [[ -n "$1" && -f "$1" ]]; then
    echo "Processing file: $1"
else
    echo "Please provide a valid filename"
fi
Remember:
  • -z = Zero length (empty string)
  • -n = Non-zero length (has content)

Common Mistakes

1. Forgetting to quote the filename

# Wrong - breaks on spaces or special chars
file="my file.txt"
[[ -f $file ]]   # Error!

# Correct - always quote
[[ -f "$file" ]]  # Works correctly

2. Confusing -e and -f

# -e returns true for directories too
[[ -e "/tmp" ]]  # True (exists)
[[ -f "/tmp" ]]  # False (not a regular file)

# Use -f when you specifically need a regular file
# Use -e when any file type is acceptable

3. Not checking existence before operations

# Wrong - may fail silently or with error
cat "$config_file"

# Correct - check first
if [[ -f "$config_file" ]]; then
    cat "$config_file"
else
    echo "Config file not found!"
    exit 1
fi

4. Using -nt/-ot without checking existence

# Risky - returns false if file doesn't exist
[[ "$backup" -nt "$source" ]]

# Safer - verify both exist
if [[ -f "$backup" && -f "$source" ]]; then
    [[ "$backup" -nt "$source" ]] && echo "Backup is current"
fi

Exercise: File Validation Script

Task: Create a comprehensive file validation script!

Requirements:

  • Check if a file path was provided (not empty)
  • Verify the file exists
  • Check if it's a regular file (not a directory)
  • Verify it's readable
  • Check if it's not empty (size > 0)
  • Report all findings
Show Solution
#!/bin/bash
# File Validation Script

file="$1"  # Get filename from argument

echo "=== File Validation Report ==="
echo ""

# Check 1: Path provided?
if [[ -z "$file" ]]; then
    echo "ERROR: No file path provided"
    echo "Usage: $0 "
    exit 1
fi
echo "File: $file"
echo ""

# Check 2: Exists?
echo -n "Exists: "
if [[ -e "$file" ]]; then
    echo "YES"
else
    echo "NO - File not found!"
    exit 1
fi

# Check 3: Regular file?
echo -n "Regular file: "
if [[ -f "$file" ]]; then
    echo "YES"
else
    echo "NO (might be directory or special file)"
fi

# Check 4: Readable?
echo -n "Readable: "
if [[ -r "$file" ]]; then
    echo "YES"
else
    echo "NO - Permission denied"
fi

# Check 5: Non-empty?
echo -n "Has content: "
if [[ -s "$file" ]]; then
    echo "YES (size > 0)"
else
    echo "NO (empty file)"
fi

# Check 6: Writable?
echo -n "Writable: "
if [[ -w "$file" ]]; then
    echo "YES"
else
    echo "NO"
fi

echo ""
echo "Validation complete!"

Summary

  • Existence: -e (any), -f (file), -d (directory), -L (symlink)
  • Permissions: -r (readable), -w (writable), -x (executable)
  • Size: -s (size > 0)
  • Types: -b (block), -c (char), -p (pipe), -S (socket)
  • Comparison: -nt (newer), -ot (older), -ef (same file)
  • Strings: -z (empty), -n (not empty)
  • Always Quote: Use [[ -f "$file" ]] to handle spaces and special characters

What's Next?

Congratulations! You've completed the Operators & Arithmetic module. You now know how to perform calculations, compare values, combine conditions, and test files. Next, we'll dive into Control Flow with if statements, case statements, and loops to put all these operators to work!