/commands/find/find-file-by-name
find . -name "*.log": find files by name or extension
- tool
- find
- versions
- GNU findutils 4.x, BSD find (macOS)
- os
- linux, macos, windows
find . -name "*.log" lists every file and directory below the current directory whose name matches *.log. Put the pattern in quotes so the shell does not expand it, use -iname to ignore case, add -type f to keep only regular files, and replace . with the directory to search (for example find /etc -name nginx.conf). The pattern is a shell glob matched against the file name only, not the full path.
Example
mkdir -p app/logs app/src old
touch app/logs/server.log app/logs/Error.LOG app/src/main.py app/README.md old/app.log.1
mkdir app/archive.log
find . -name '*.log' | sort
echo ===
find . -type f -iname '*.log' | sort
echo ===
find . -name '*.log*' -not -path './old/*' | sortOutput
./app/archive.log ./app/logs/server.log === ./app/logs/Error.LOG ./app/logs/server.log === ./app/archive.log ./app/logs/server.log
The first search also returns the directory archive.log, because -name matches directories too. -type f -iname keeps only files and matches Error.LOG regardless of case. The third command widens the glob and excludes everything under ./old.
Common forms
| Command | Finds |
|---|---|
| find . -name 'nginx.conf' | Files or directories named exactly nginx.conf |
| find . -type f -name '*.py' | Regular files ending in .py |
| find . -iname '*.jpg' | Ignoring case: .jpg, .JPG, .Jpg |
| find . -type d -name node_modules -prune | node_modules directories, without descending into them |
| find . -name '*.js' -not -path '*/node_modules/*' | JavaScript files outside node_modules |
| find . \( -name '*.jpg' -o -name '*.png' \) | Either extension; the parentheses group the -o |
| find . -maxdepth 1 -name '*.txt' | Only in the current directory, not below |
| find / -name hosts 2>/dev/null | Search the whole system and hide Permission denied lines |
| find . -regex '.*/[0-9]+\.csv' | Full path matched with a regex (GNU default: emacs syntax) |
Act on the results
mkdir -p proj/a proj/b
printf 'one\n' > proj/a/x.txt
printf 'two\nthree\n' > proj/b/y.txt
find proj -name '*.txt' -exec wc -l {} + | sort -k2
find proj -name '*.txt' -print0 | xargs -0 grep -l threeOutput
1 proj/a/x.txt 2 proj/b/y.txt 3 total proj/b/y.txt
-exec cmd {} + runs one command with many file names; -print0 | xargs -0 does the same and survives names with spaces and newlines. Both avoid Argument list too long.
Pitfalls
- Unquoted globs.
find . -name *.logworks only while no.logfile exists in the current directory; with two of them find stops withpaths must precede expression. - Option order.
-maxdepthis a global option: put it right after the path, or GNU find warns that it was specified after-name. -owithout parentheses.find . -name '*.jpg' -o -name '*.png' -exec ...applies-execonly to the PNG files, because-abinds tighter than-o. Group the names with\( ... \).- macOS. BSD find needs a path (
find . -name x, notfind -name x) and does not have every GNU option, but-name,-iname,-path,-type,-maxdepthand-prunework the same.
If the database-backed locate command is installed, locate nginx.conf is faster for whole-system lookups, but it only knows files that existed when its index was last updated.
FAQ
Why does find -name *.log fail with paths must precede expression?
Without quotes the shell expands *.log to the matching names in the current directory before find runs, so find receives several words after -name. Quote the pattern, find . -name '*.log', so find does the matching itself in every directory.
How do I hide the Permission denied lines when searching from /?
Send standard error to /dev/null, find / -name nginx.conf 2>/dev/null. The messages come from directories your user cannot read; the search continues past them.
How do I match the full path instead of the file name?
Use -path, as in find . -path '*/config/*.yml'. -name only looks at the last part of the path, so a pattern with a slash in it never matches -name.