How to check if a file exists in Bash

Check if a file exists in Bash with [ -f "$file" ], test for directories with -d, and check readability/writability with -r and -w. Copy-paste examples.

Tldr

Use `[ -e "$file" ]` to check that a path exists at all, `[ -f "$file" ]` to require it be a regular file, and `[ -d "$file" ]` to require a directory. Always quote the variable to handle spaces and empty values safely.

Intro

Bash provides a family of file test operators for existence, type, and permission checks. Picking the right one avoids both false positives (matching a directory when you wanted a file) and quoting bugs.

Steps

Name

Check that any path exists

Text

-e is true for any existing filesystem entry: regular file, directory, symlink, device, etc.

Name

Check for a regular file specifically

Text

-f is true only for regular files, not directories or special files. This is the most common check before reading a file.

Name

Check for a directory

Text

-d is true for directories. Combine with -e checks to give clearer error messages.

Name

Check readability and writability

Text

-r and -w check the effective permissions for the current user, which is more reliable than parsing ls -l output.

Name

Handle symlinks correctly

Text

-e follows symlinks and reports false for a broken (dangling) symlink. Use -L to detect that the path is a symlink regardless of whether the target exists.

Faq

Q

What is the difference between -e and -f?

A

-e is true for anything that exists at that path (file, directory, device, symlink). -f narrows that to regular files only, so it is what you want before opening a file for reading.

Q

Why does [ -f "$file" ] fail even though ls shows the file?

A

Common causes are an unquoted variable containing spaces splitting into multiple arguments, a trailing newline from command substitution, or the variable actually holding a relative path resolved from a different working directory. Quote the variable and print it with `declare -p file` to check.

Q

Can I check multiple files in one condition?

A

Yes: `if [ -f "$a" ] && [ -f "$b" ]; then ...` or use [[ ]] with && the same way. Avoid `-a` inside a single [ ] test — it is deprecated and ambiguous.