FHS and Finding Files - find, locate, and the FHS
What You Will Achieve
- Explain the purpose of the main directories in the FHS (Filesystem Hierarchy Standard)
- Decide where files belong using the "shareable/unshareable" and "static/variable" classifications
- Use the key
findtests (-name/-type/-size/-mtime/-perm/-user/-newer/-exec) appropriately - Understand how
locate/updatedbwork and the role of/etc/updatedb.conf - Answer, with reasoning, when to use
findvslocate, andwhich/whereis/type
This is the core of LPIC-1 objective 104.7 "Find system files and place files in the correct location". It is the skill of judging where config files and logs belong using the FHS, then actually locating them with find / locate.
Where Does Each File Belong in the FHS
FHS 3.0 is the specification that standardizes the Linux directory structure. Each directory has a clear role, and the type of file determines where it belongs. Start with the main directories that appear frequently on the exam.
| Directory | Purpose in the FHS |
|---|---|
/bin |
Essential user command binaries (for all users) |
/sbin |
System binaries |
/etc |
Host-specific system configuration (static, unshareable) |
/lib |
Essential shared libraries and kernel modules |
/usr |
Shareable, read-only programs and data |
/usr/bin |
Most user commands |
/usr/sbin |
Non-essential system administration commands |
/usr/local |
Software installed locally by the administrator |
/var |
Variable data that changes during operation |
/var/log |
Log files |
/var/spool |
Spool data such as print and mail |
/tmp |
Temporary files |
/home |
Regular users' home directories |
/root |
Home directory for the root user |
/boot |
Static files of the boot loader and the kernel |
/dev |
Device files |
/proc |
Virtual filesystem of process and kernel information |
/sys |
Virtual filesystem of device and kernel information |
/opt |
Add-on application software packages |
/mnt |
Mount point for a temporarily mounted filesystem |
/media |
Mount point for removable media |
/srv |
Data for services provided by this system |
/bin and /sbin must hold "commands needed before /usr is mounted". Right after boot or in single-user mode, /usr may be a separate partition that is not yet mounted, so the minimal recovery commands are placed on the root partition by design.
/proc and /sys are virtual filesystems with no on-disk substance. /proc/cpuinfo and /sys/class/ are information the kernel generates dynamically; they are not a place to "save" files by editing.
What Are Shareable/Unshareable and Static/Variable
The FHS classifies files along two independent axes: "shareable vs unshareable" and "static vs variable". Once you understand this, why /usr and /var are separated finally clicks.
- Shareable: files stored on one host and usable by other hosts (e.g., programs under
/usr,/home) - Unshareable: files specific to that host (e.g., configuration in
/etc, device lock files) - Static: files that do not change without administrator intervention (binaries, libraries, documentation)
- Variable: files that normally change during operation (logs, spool, cache)
| Shareable | Unshareable | |
|---|---|---|
| Static | /usr, /opt |
/boot, /etc |
| Variable | /var/mail, /var/spool/news |
/var/run, /var/lock |
The point of this classification is to let you put static files on read-only media or apply a different backup policy to variable files only. Historically UNIX mixed both types, but consolidating variable files into /var allows /usr to be mounted read-only as a separate filesystem.
Choosing Between /usr and /usr/local
Software installed by the distribution's package manager goes in /usr (/usr/bin, etc.), while software the administrator installs manually goes in /usr/local (/usr/local/bin, etc.). The reason to separate the roles is clear, and not mixing them is the foundation of maintainable systems.
The /usr hierarchy is the package manager's (apt / dnf, etc.) territory and may be overwritten by OS upgrades or package updates. By contrast, /usr/local is untouched by package management, so putting software built from source or your own scripts there avoids accidents where an OS update deletes or conflicts with them.
Copying a self-built command directly into /usr/bin risks being overwritten or conflicting when a package of the same name is updated. The FHS intent is to place manual installs in /usr/local.
Using the Main find Tests
find walks a given directory in real time and locates files matching your conditions. Unlike locate, it always reflects the current state and can chain follow-up actions (deletion, permission change, etc.) in one go.
Step 1: Narrow by name and type
find /etc -name '*.conf' -type f
/etc/ssh/sshd_config.conf /etc/logrotate.conf /etc/resolv.conf
-name matches the filename (the base name at the end of the path) against a shell pattern. -type f means a regular file, -type d a directory, and -type l a symbolic link. Use -iname to ignore case.
Step 2: Search by size and modification time
find /var/log -type f -size +100M find /home -type f -mtime -7
/var/log/journal/system.journal /home/user/report-draft.md
-size +100M matches files larger than 100 MiB. The suffixes are c (bytes), k (KiB), M (MiB), G (GiB); + means "greater than" and - means "less than". -mtime -7 means "modified within 7 x 24 hours". Note that -mtime +1 means "modified at least 2 days ago" (fractional parts are discarded).
Step 3: Search by owner and permissions
find /home -user alice -perm -0200 find / -perm /4000 -type f 2>/dev/null
/home/alice/notes.txt /usr/bin/passwd
-user alice matches files owned by alice. -perm /4000 means "any of the specified bits are set" (here SUID), while a - prefix such as -perm -0664 means "all of the specified bits are set". This is useful for auditing SUID bits.
Step 4: Batch-process the search results
find /tmp -name '*.tmp' -mtime +7 -exec rm {} +
find . -name '*.txt' -newer reference.txt -exec ls -l {} \;-rw-r--r-- 1 user user 320 May 30 10:00 ./new-note.txt
-exec command {} \; runs the command once per matched file, with {} replaced by the filename. -exec command {} + appends multiple files to a single command line (similar to xargs), which is more efficient. -newer reference.txt selects files modified more recently than the reference file.
Escape the semicolon in -exec ... {} \; as \; (or ';') so the shell does not interpret it. Forgetting this causes errors such as find: missing argument to -exec.
How locate and updatedb Work
locate does not walk the filesystem directly; it searches a pre-built filename database, making it very fast. Many distributions use the mlocate implementation.
Step 1: Search quickly with locate
locate sshd_config locate -i readme
/etc/ssh/sshd_config /usr/share/doc/openssh-server/README
locate instantly returns names registered in the database. Use -i (--ignore-case) to ignore case. Note, however, that the results are a snapshot from "the last time the database was updated".
Step 2: Update the database with updatedb
sudo updatedb locate newfile.txt
/home/user/newfile.txt
updatedb rebuilds the database. Newly created or deleted files are not reflected in locate results until you run updatedb. Many environments run it periodically via cron, but to find a file you just created, a manual update is needed.
Step 3: Tune the targets in /etc/updatedb.conf
grep -E 'PRUNEPATHS|PRUNEFS' /etc/updatedb.conf
PRUNEFS="NFS nfs nfs4 afs binfmt_misc ..." PRUNEPATHS="/tmp /var/spool /media /var/lib/os-prober ..."
Tune the indexing targets in /etc/updatedb.conf. PRUNEPATHS lists directories to exclude from indexing, and PRUNEFS lists filesystem types to exclude. This prevents wasteful indexing of /tmp or network mounts.
When to Use find vs locate
Use find when you need real-time accuracy, and locate when you just want a fast name search. They do not compete; choose by use case.
find walks the disk so it is slow, but it is always current and supports rich conditions (size, modification time, permissions, owner) plus follow-up processing via -exec. locate reads the database so it is instant, but it is limited to name-based searches and does not reflect the current state until after updatedb. "Where is the file I just created" suits find; "what is the path of that config file" suits locate.
The Difference Between which / whereis / type
The three tools that look up a command's "location" have different purposes. Use which for the binary that gets executed, whereis for the full set of related files, and type for how the shell interprets a name.
which python3 whereis ls type cd type ll
/usr/bin/python3 ls: /usr/bin/ls /usr/share/man/man1/ls.1.gz cd is a shell builtin ll is aliased to `ls -alF'
which: returns the full path of the command executed fromPATHwhereis: locates the binary, source, and manual page files of a commandtype: a shell builtin; it indicates whether a name is interpreted as an alias, builtin, function, keyword, or file
A shell builtin like cd is not found by which (no executable file exists). "Why is which cd empty" is answered by type cd, which tells you it is a builtin.
Common Mistakes and Fixes
- locate results are stale: a just-created file does not appear / a deleted file remains. Run
sudo updatedbto refresh the database - Forgetting the semicolon for
-exec: omitting\;infind ... -exec rm {} \;causesfind: missing argument to -exec. Terminate with\;or+ - Confusing
/usrand/usr/local: putting self-built software in/usr/binconflicts on package updates. Place manual installs in/usr/local - Misreading the sign of
-mtime: mixing up-mtime -1(within 24 hours) and-mtime +1(at least 2 days ago). "Today's files" is-mtime -1 - Looking up a shell builtin with which:
which cdis empty and confusing. Usetypeto check builtins and aliases
Troubleshooting
Symptom: locate cannot find a just-created file
Cause: locate reads a database and only has a snapshot from when updatedb ran
Check:
locate newfile.txt
Fix: Run sudo updatedb to refresh the database, then search again. To reliably find the current state, use find.
Symptom: find -exec gives "missing argument to -exec"
Cause: The semicolon terminating the command is not escaped
Check:
find . -name '*.log' -exec ls -l {} \;Fix: Always terminate the -exec command with \; (run one at a time) or + (run in batch).
Symptom: Running find / produces many permission errors
Cause: You are walking directories a regular user cannot read (parts of /proc or other users' areas)
Check:
find / -name target.conf 2>/dev/null
Fix: Discard standard error with 2>/dev/null, or narrow the scope to /etc etc. To reliably search the whole system, use sudo find.
Completion Checklist
- [ ] Reviewed the purpose of the main FHS directories in a table
- [ ] Understood the shareable/unshareable and static/variable classifications
- [ ] Tried
findsearches by name, type, size, modification time, permissions, and owner - [ ] Confirmed the difference between
-exec {} \;and-exec {} + - [ ] Reflected updates with
sudo updatedbafter alocatesearch - [ ] Used
which/whereis/typeappropriately
Summary
| Goal | Command / Location | Point |
|---|---|---|
| Where config files go | /etc (static, unshareable) |
Host-specific |
| Where variable data goes | /var (logs, spool) |
Changes during operation |
| Manually installed software | /usr/local |
Separated from package management |
| Conditional search + action | find -size/-mtime/-exec |
Real-time, current, post-process |
| Fast name search | locate + sudo updatedb |
DB lookup, needs update |
| Location of an executable | which / whereis / type |
Choose by use case |
The FHS is the map for judging the "correct location" of a file, while find / locate are the tools for finding the target file on that map. Master both, and you can trace configs and logs without getting lost even on an unfamiliar system.