Finding Files
On a real Ubuntu server you quickly lose track of where things live. Config files, log files, scripts, and stray backups end up scattered across the filesystem (the tree of folders that holds every file on the machine). Linux gives you three core tools for finding them: find for powerful, real-time searches, locate for instant lookups from a pre-built index, and which for finding where a command (program) actually lives. Knowing these turns “I can’t find that file” into a five-second job.
find — search the filesystem in real time
find walks through directories one by one, checking each file against the rules you give it. It is slower than locate because it looks at the disk live, but it is always up to date and can match on almost any property: name, type, size, age, owner, and permissions.
The basic shape is always find <where-to-look> <what-to-match>.
Find by name
This is the most common use. Search /etc (the directory that holds system-wide configuration) for every file ending in .conf:
find /etc -name "*.conf"
Output:
/etc/ufw/sysctl.conf
/etc/resolv.conf
/etc/nginx/nginx.conf
/etc/ssh/ssh_config.d/50-cloud-init.conf
/etc/sysctl.conf
Always quote the pattern ("*.conf"). Without quotes the shell tries to expand the * itself before find ever sees it, which gives wrong results.
Use -iname instead of -name for a case-insensitive match (so README, readme, and ReadMe all match):
find /var/www -iname "index.html"
Searching from
/(the very top of the filesystem) scans the entire disk and can take a long time. Always start from the narrowest directory you can, such as/etcor/var/log, not/.
Find by type
The -type flag limits results to a kind of entry. The two you use most are f for a regular file and d for a directory.
# Only directories named "logs" under /var
find /var -type d -name "logs"
# Only regular files (skip directories) ending in .log
find /var/log -type f -name "*.log"
| Type letter | Matches |
|---|---|
f | Regular file |
d | Directory |
l | Symbolic link (a shortcut pointing to another file) |
s | Socket |
b / c | Block / character device |
Find by size
The -size flag finds files above or below a size. + means larger than, - means smaller than, and the suffix sets the unit: k (kilobytes), M (megabytes), G (gigabytes).
# Files larger than 100 MB under /var (great for hunting disk hogs)
find /var -type f -size +100M
Output:
/var/log/journal/9f2.../system.journal
/var/lib/docker/overlay2/abc123/diff/big.tar
Find by modification time
-mtime matches by how many days ago a file’s contents last changed. -mtime -1 means changed in the last 24 hours; -mtime +7 means not changed in over 7 days. For minutes, use -mmin.
# Files in /etc changed in the last day (handy after a config edit you forgot)
find /etc -type f -mtime -1
# Log files not touched in over 30 days, ready for cleanup
find /var/log -type f -name "*.log" -mtime +30
Acting on what you find
Add -delete to remove matches, or -exec to run any command on each match. The {} is replaced by the file path, and \; ends the command.
# Show details of every .conf file (ls -lh runs once per file)
find /etc -name "*.conf" -exec ls -lh {} \;
find ... -deletehas no undo. Always run the same command without-deletefirst to confirm the list is exactly what you expect, then add the flag.
locate — instant lookups from an index
locate does not scan the disk. It searches a database (a pre-built index of every filename) that Ubuntu updates on a schedule, so results come back instantly even when searching the whole system. The trade-off is that the index can be slightly stale: a file created two minutes ago may not appear yet.
On Ubuntu 22.04 and 24.04, install it and build the index first:
sudo apt update
sudo apt install plocate
sudo updatedb
Then search by any part of the path:
locate nginx.conf
Output:
/etc/nginx/nginx.conf
/usr/share/doc/nginx-common/examples/nginx.conf
Use updatedb (run automatically each night by a systemd timer) to refresh the index after creating new files. Use locate -i pattern for a case-insensitive search.
find vs locate — when to use which
| Question | find | locate |
|---|---|---|
| Speed | Slower (live scan) | Instant (reads index) |
| Up to date? | Always current | Only as fresh as last updatedb |
| Search by size/time/owner? | Yes | No, name/path only |
| Run a command on results? | Yes (-exec) | No |
| Needs install on Ubuntu? | No, built in | Yes (plocate) |
Use locate for a quick “where is that file by name” when you do not need filters. Use find when you need to match on size, age, type, or owner, or when the file might be brand new.
which — find where a command lives
which answers “when I type this command, which program actually runs?” It searches the directories listed in your PATH (the list of folders the shell looks through for commands) and prints the full path of the first match.
which python3
which docker
Output:
/usr/bin/python3
/usr/bin/docker
If which prints nothing, the command is not installed or not on your PATH. For more detail, including aliases and shell built-ins, use type instead:
type ls
Output:
ls is aliased to `ls --color=auto'
Best Practices
- Start
findfrom the narrowest directory possible (/etc,/var/log) instead of/to avoid slow, system-wide scans. - Always quote name patterns (
"*.log") so the shell does not expand the*beforefindsees it. - Preview matches before destructive actions: run the search alone, then add
-deleteor-exec rmonly after confirming the list. - Reach for
locatefor fast name-only lookups, but runsudo updatedbfirst if you are searching for recently created files. - Combine filters in one
findcall (-type f -name "*.log" -mtime +30) rather than piping throughgrepfor speed and clarity. - Use
whichto confirm a tool is installed andtypewhen you need to see aliases or shell built-ins too.