/commands/find/find-empty-files-directories
find . -empty: find and delete empty files and directories
- tool
- find
- versions
- GNU findutils 4.x, BSD find (macOS)
- os
- linux, macos, windows
find . -type f -empty lists files of size 0 and find . -type d -empty lists directories that contain nothing. Check the list first, then add -delete to remove them: find . -type d -empty -delete. -delete processes the deepest entries first, so a directory that becomes empty after its empty subdirectories are removed is deleted too. The starting directory itself is removed as well if it ends up empty; use -mindepth 1 to keep it.
Example
mkdir -p data/a/b/c data/keep data/logs
touch data/empty.txt data/logs/today.log data/keep/.gitkeep
printf 'x\n' > data/notes.txt
echo "empty files:"
find data -type f -empty | sort
echo "empty directories:"
find data -type d -empty | sort
find data -mindepth 1 -type d -empty -delete
echo "left after -delete:"
find data | sortOutput
empty files: data/empty.txt data/keep/.gitkeep data/logs/today.log empty directories: data/a/b/c left after -delete: data data/empty.txt data/keep data/keep/.gitkeep data/logs data/logs/today.log data/notes.txt
Before deleting, only data/a/b/c is an empty directory: a and b each contain one directory. -delete removed c, then b and a as each became empty. data/keep survived because of its .gitkeep, and data/logs because it contains a file, even an empty one.
Variants
| Command | Does |
|---|---|
| find . -type f -empty | List empty files |
| find . -type d -empty | List empty directories |
| find . -empty | Both |
| find . -type f -empty -delete | Delete empty files |
| find . -mindepth 1 -type d -empty -delete | Delete empty directories, keep the starting directory |
| find . -type d -empty -not -path "./.git/*" -delete | Skip the .git directory |
| find . -depth -type d -empty -exec rmdir {} + | Same result with rmdir, which refuses to remove anything not empty |
| find . -type f -empty | wc -l | Count empty files |
Safety
rmdir is a safe alternative for directories: it fails with Directory not empty instead of removing content, so a wrong pattern cannot delete files. Empty files are sometimes meaningful (lock files, __init__.py in Python packages, .gitkeep), so limit the search with -name or -path when cleaning a project.
Platform notes
GNU find (Linux, Git Bash) and BSD find (macOS) both support -empty, -delete, -mindepth and -depth. On a minimal find without -empty, -size 0 selects empty files. If find cannot delete an entry (no permission, or a file locked by another program on Windows), it prints an error for that entry, continues with the rest and exits with a non-zero status.
FAQ
Why does -delete not remove a directory that only contains empty directories?
It does with GNU and BSD find, because -delete implies -depth: the contents of a directory are processed before the directory itself, so the inner empty directories go first and the parent is empty by the time find reaches it. With -exec rmdir {} ; you must add -depth yourself.
Does -empty count a file that contains only a newline?
No. -empty is true only for files of size 0 and directories with no entries. A file with a single newline has size 1. Use -size -2c to include files of 0 or 1 byte, and check them before deleting.
How do I keep a placeholder like .gitkeep from being deleted?
A directory with a .gitkeep file is not empty, so -type d -empty skips it. If the .gitkeep files are empty themselves, exclude them from the file search with -not -name .gitkeep.