Find & Locate¶
find is one of the most powerful tools in Unix — it can locate files by any combination of name, size, age, permissions, or content, and immediately run commands on everything it finds.
Learning Objectives¶
- Search for files by name, type, size, and modification time with
find - Execute commands on found files using
-execandxargs - Use
locatefor fast filename searches - Use
which,type, andcommand -vto find executables
find — Search the Filesystem¶
find /path -name "filename" # find by exact name
find /path -name "*.log" # wildcard in name
find /path -iname "*.LOG" # case-insensitive
find /path -type f # files only
find /path -type d # directories only
find /path -type l # symlinks only
Searching by Size¶
find /home -size +100M # larger than 100 MB
find /tmp -size -1k # smaller than 1 KB
find /var -size +10M -size -500M # between 10 MB and 500 MB
Size suffixes: c (bytes), k (KB), M (MB), G (GB).
Searching by Modification Time¶
find /var/log -mtime -1 # modified in the last 1 day
find /home -mtime +30 # not modified in 30+ days
find /tmp -mmin -60 # modified in the last 60 minutes
find /home -newer /etc/passwd # newer than /etc/passwd
Searching by Permissions¶
find /home -perm 644 # exact permission match
find /home -perm -u+x # at least executable by owner
find / -perm /4000 2>/dev/null # setuid files
find /home -perm /o+w # world-writable files (security check)
Executing Commands on Found Files¶
-exec — Run a Command on Each Match¶
find /tmp -name "*.tmp" -exec rm {} \; # delete all .tmp files
find /home -name "*.sh" -exec chmod +x {} \; # make scripts executable
find /var/log -name "*.log" -exec ls -lh {} \; # list matching files
The {} is a placeholder for the matched file. \; ends the -exec expression.
# Using + instead of \; — passes all files at once (more efficient)
find /home -name "*.txt" -exec cat {} +
{}+ is faster than {}\;
-exec command {} \; runs the command once per file. -exec command {} + collects all files and runs the command once with all of them as arguments. Use + when the command accepts multiple file arguments.
xargs — Build and Execute Commands from stdin¶
xargs is often more flexible than -exec:
find /tmp -name "*.tmp" | xargs rm
find /home -name "*.sh" | xargs chmod +x
find . -name "*.py" | xargs grep -l "import os"
Filenames with spaces and xargs
If filenames contain spaces, xargs will split them incorrectly. Use null-delimited output:
-print0 outputs names separated by null bytes; -0 tells xargs to split on null bytes.
Combining find Conditions¶
find /home -name "*.log" -size +10M -mtime +7 # .log files, >10MB, >7 days old
find /home -name "*.tmp" -o -name "*.temp" # either match (-o = OR)
find /home ! -name "*.keep" # NOT matching (! = negation)
locate — Fast Name Search¶
locate searches a pre-built database instead of scanning the filesystem live. Much faster for simple name searches.
locate passwd # find all files with "passwd" in the name
locate -i bashrc # case-insensitive
locate "*.conf" | head -20 # find config files
locate database is updated daily
locate searches a database that is typically updated once a day by updatedb. Files created after the last update will not appear. Run sudo updatedb to refresh it immediately.
Finding Executables¶
which python3 # path to an executable in $PATH
type python3 # type: builtin, alias, function, or path
command -v python3 # POSIX-portable, returns path or nothing
Common Mistakes¶
find without -maxdepth on large trees
find / or find /home without constraints can take minutes on large filesystems and produce millions of results. Always add -maxdepth N, a name filter, or a path constraint when possible.
Forgetting 2>/dev/null on system-wide finds
Running find / or find /etc without 2>/dev/null will output many "Permission denied" errors for files owned by root. Redirect stderr to suppress them: find / -name "*.conf" 2>/dev/null.
Practice Exercises¶
Warm-Up (run and observe)¶
- Run
find ~ -name "*.sh" -type f. How many shell scripts are in your home directory? - Run
find /var/log -mtime -1 -type f. What was modified in the last 24 hours? - Run
find /tmp -size +0 -type f. What non-empty files are in/tmp?
Main (write a short script)¶
Create ~/scripts/find_large.sh that finds files over a given size in a given directory:
#!/usr/bin/env bash
set -euo pipefail
DIR="${1:-.}"
SIZE="${2:-100M}"
echo "Files larger than $SIZE in $DIR:"
echo ""
find "$DIR" -type f -size "+$SIZE" -print0 \
| xargs -0 ls -lh 2>/dev/null \
| sort -k5 -rh \
| awk '{ print $5, $9 }'
Stretch¶
- Use
findto identify all world-writable files in/home(permissions includeo+w). Why is this a security concern? - Write a command using
findandxargsthat counts the total number of lines across all.pyfiles under the current directory. - Research
find -prune. Use it to search a directory tree while excluding a specific subdirectory (e.g., search~/projectsbut skip~/projects/node_modules).
Interview Questions¶
- What is the difference between
findandlocate?
Show answer
find scans the filesystem in real time — it always returns current results but is slower. locate searches a pre-built database — it is much faster but may be out of date (updated daily by updatedb). Use locate for quick searches when a slightly stale result is acceptable; use find when accuracy is required or when you need to filter by attributes like size or modification time.
- What is the difference between
-exec command {} \;and-exec command {} +?
Show answer
\; runs the command once per file found — if 1000 files match, the command runs 1000 times. + collects all matching files and passes them all to a single invocation of the command, like xargs. + is significantly faster for large result sets. Use + when the command accepts multiple arguments; use \; when the command can only process one file at a time.
- Why do you need
-print0withfindand-0withxargs?
Show answer
By default, find separates results with newlines and xargs splits on whitespace. Filenames can legally contain spaces and newlines, which would cause incorrect splitting. The null byte (\0) cannot appear in a filename, making it a safe delimiter. -print0 outputs filenames separated by null bytes; -0 tells xargs to split on null bytes instead of whitespace.