FHS とファイル配置・検索 - find/locate と FHS【LPIC-1 104.7】

FHS とファイル配置・検索 - find/locate と FHS【LPIC-1 104.7】

この記事で達成できること

  • FHS(Filesystem Hierarchy Standard)の主要ディレクトリの用途を説明できる
  • 「共有可能/非共有」「静的/可変」の区分でファイルの置き場所を判断できる
  • find の主要テスト(-name / -type / -size / -mtime / -perm / -user / -newer / -exec)を使い分けられる
  • locate / updatedb の仕組みと /etc/updatedb.conf を理解できる
  • findlocatewhich / whereis / type の使い分けを根拠付きで答えられる

LPIC-1 主題 104.7「システムファイルを見つけ、正しい位置に配置する」の中核。設定ファイルやログがどこにあるべきかを FHS で判断し、find / locate で実際に探し当てる技術。

FHS のどこに何を置くか

FHS 3.0 は Linux のディレクトリ構造を標準化した仕様。各ディレクトリには明確な役割があり、ファイルの種類で置き場所が決まる。まずは試験頻出の主要ディレクトリを押さえる。

ディレクトリ FHS 上の用途
/bin 全ユーザーが使う必須コマンドのバイナリ
/sbin システム管理用のバイナリ
/etc ホスト固有のシステム設定(静的・非共有)
/lib 必須の共有ライブラリとカーネルモジュール
/usr 共有可能・読み取り専用のプログラムとデータ
/usr/bin 一般ユーザー向けの大半のコマンド
/usr/sbin 起動に必須でないシステム管理コマンド
/usr/local 管理者がローカルに導入したソフト
/var 運用中に変化する可変データ
/var/log ログファイル
/var/spool 印刷・メール等のスプールデータ
/tmp 一時ファイル
/home 一般ユーザーのホームディレクトリ
/root root ユーザーのホームディレクトリ
/boot ブートローダの静的ファイルとカーネル
/dev デバイスファイル
/proc プロセス・カーネル情報の仮想ファイルシステム
/sys デバイス・カーネルの仮想ファイルシステム
/opt 追加アプリケーションソフトウェアパッケージ
/mnt 一時的にマウントするファイルシステムの場所
/media リムーバブルメディアのマウントポイント
/srv このシステムが提供するサービス用データ

/bin/sbin には「/usr をマウントする前に必要なコマンド」を置く決まりがある。起動直後やシングルユーザーモードでも /usr が別パーティションで未マウントの状況があるため、最低限の復旧コマンドはルートパーティション側に置く設計になっている。

/proc/sys はディスク上に実体がない仮想ファイルシステム。/proc/cpuinfo/sys/class/ はカーネルが動的に生成する情報で、編集してファイルを「保存」する場所ではない。

共有可能/非共有・静的/可変とは

FHS は 2 つの独立した軸でファイルを分類する。「共有可能(shareable)か非共有(unshareable)か」と「静的(static)か可変(variable)か」。この区分が分かると、なぜ /usr/var が分かれているのかが腑に落ちる。

  • 共有可能: 1 台に置いて複数ホストから使えるファイル(例: /usr のプログラム、/home
  • 非共有: そのホスト固有のファイル(例: /etc の設定、デバイスのロックファイル)
  • 静的: 管理者が手を入れない限り変わらないファイル(バイナリ・ライブラリ・ドキュメント)
  • 可変: 運用中に通常変化するファイル(ログ・スプール・キャッシュ)
共有可能 非共有
静的 /usr/opt /boot/etc
可変 /var/mail/var/spool/news /var/run/var/lock

この分類の狙いは、静的ファイルを読み取り専用メディアに置いたり、可変ファイルだけ別のバックアップ方針にしたりできるようにすること。歴史的に UNIX は両者を混在させていたが、可変ファイルを /var に集約することで /usr を読み取り専用で別マウントできるようになった。

/usr と /usr/local の使い分け

ディストリビューションのパッケージ管理が入れるソフトは /usr/usr/bin 等)に、管理者が手動で導入したローカルなソフトは /usr/local/usr/local/bin 等)に置く。役割を分ける理由は明確で、混ぜないことがシステム保守の前提になる。

/usr 配下はパッケージマネージャ(apt / dnf 等)の管理領域で、OS アップグレードやパッケージ更新で上書きされる可能性がある。一方 /usr/local はパッケージ管理が触らない領域なので、ソースからビルドしたソフトや自前スクリプトをここに置けば、OS 更新で消える・衝突する事故を避けられる。

自前ビルドしたコマンドを /usr/bin に直接コピーすると、同名パッケージの更新時に上書き・衝突するおそれがある。手動導入は /usr/local に置くのが FHS の意図。

find の主要テストを使い分ける

find は指定ディレクトリ以下を実時間で走査し、条件に合うファイルを探す。locate と違って常に最新の状態を反映し、検索後の処理(削除・権限変更等)まで一気にできるのが強み。

Step 1: 名前と種類で絞り込む

find /etc -name '*.conf' -type f
/etc/ssh/sshd_config.conf
/etc/logrotate.conf
/etc/resolv.conf

-name はファイル名(パス末尾のベース名)をシェルパターンで照合する。-type f は通常ファイル、-type d はディレクトリ、-type l はシンボリックリンクを表す。大文字小文字を無視するなら -iname を使う。

Step 2: サイズと更新日時で探す

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 は 100 MiB を超えるファイル。接尾辞は c(バイト)、k(KiB)、M(MiB)、G(GiB)で、+ は「より大きい」、- は「より小さい」を意味する。-mtime -7 は「7×24 時間以内に更新」。-mtime +1 は「2 日以上前に更新」を意味する点に注意(端数は切り捨て)。

Step 3: 所有者と権限で探す

find /home -user alice -perm -0200
find / -perm /4000 -type f 2>/dev/null
/home/alice/notes.txt
/usr/bin/passwd

-user alice は所有者が alice のファイル。-perm /4000 は「指定ビットのいずれかが立っている」(ここでは SUID)を意味し、-perm -0664 のように - を付けると「指定ビットがすべて立っている」になる。SUID ビットの調査などに使える。

Step 4: 検索結果をまとめて処理する

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 {} \; は一致したファイルごとにコマンドを 1 回実行し、{} がファイル名に置換される。-exec command {} + は複数ファイルをまとめて 1 つのコマンドラインに渡す(xargs に近い動作)ため効率的。-newer reference.txt は基準ファイルより新しく更新されたものを選ぶ。

-exec ... {} \; のセミコロンはシェルに解釈されないよう \; とエスケープする(または ';')。これを忘れると find: missing argument to -exec 等のエラーになる。

locate と updatedb の仕組み

locate はファイルシステムを直接走査せず、あらかじめ作られたファイル名データベースを検索するため非常に高速。多くのディストリビューションでは mlocate 実装が使われる。

Step 1: locate で高速検索する

locate sshd_config
locate -i readme
/etc/ssh/sshd_config
/usr/share/doc/openssh-server/README

locate はデータベースに登録された名前を瞬時に返す。-i--ignore-case)で大文字小文字を無視できる。ただし結果は「データベースを最後に更新した時点」のスナップショットである点に注意。

Step 2: updatedb でデータベースを更新する

sudo updatedb
locate newfile.txt
/home/user/newfile.txt

updatedb がデータベースを再構築する。新規作成・削除したファイルは updatedb を実行するまで locate の結果に反映されない。多くの環境では cron 等で定期実行されるが、作成直後のファイルを探すなら手動更新が必要。

Step 3: /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 ..."

/etc/updatedb.conf で索引対象を調整する。PRUNEPATHS は索引から除外するディレクトリ、PRUNEFS は除外するファイルシステム種別。これにより /tmp やネットワークマウント等が無駄に索引されるのを防いでいる。

find と locate はどう使い分けるか

リアルタイム性が必要なら find、名前だけ高速に探すなら locate。両者は競合せず、用途で使い分けるのが正解。

find はディスクを実走査するため遅いが、常に最新で、サイズ・更新日時・権限・所有者といった多彩な条件と、-exec による後続処理が使える。locate はデータベース参照で一瞬だが、名前ベースの検索に限られ、updatedb 後でないと最新状態を反映しない。「さっき作ったファイルがどこか」は find、「あの設定ファイルのパスは」は locate が向く。

which / whereis / type の違い

コマンドの「場所」を調べる 3 つは目的が異なる。実行されるバイナリの場所は which、関連ファイル一式は whereis、シェルがどう解釈するかは type

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: PATH 上から実行されるコマンドのフルパスを返す
  • whereis: コマンドのバイナリ・ソース・man ページの場所を探す
  • type: シェル組み込み。その名前がエイリアス・組み込み・関数・キーワード・ファイルのどれとして解釈されるかを示す

cd のようなシェル組み込みコマンドは which では見つからない(実行ファイルが存在しないため)。「なぜ which cd が空なのか」は type cd が組み込みだと教えてくれる。

よくあるミスと対処

  • locate の結果が古い: 作ったばかりのファイルが出ない / 消したはずのファイルが残る。sudo updatedb でデータベースを更新する
  • -exec のセミコロン忘れ: find ... -exec rm {} \;\; を書かず find: missing argument to -exec になる。\; または + で終端する
  • /usr/usr/local の混同: 自前ビルドのソフトを /usr/bin に入れてパッケージ更新で衝突。手動導入は /usr/local に置く
  • -mtime の符号誤解: -mtime -1(24 時間以内)と -mtime +1(2 日以上前)を取り違える。「今日のファイル」は -mtime -1
  • which でシェル組み込みを探す: which cd が空で戸惑う。組み込み・エイリアスの確認は type を使う

トラブルシューティング

症状: locate で作成直後のファイルが見つからない

原因: locate はデータベースを参照し、updatedb 実行時点のスナップショットしか持たない

確認:

locate newfile.txt

対処: sudo updatedb でデータベースを更新してから再検索する。最新状態を確実に探すなら find を使う。

症状: find -exec でエラー「missing argument to -exec」

原因: コマンド終端のセミコロンがエスケープされていない

確認:

find . -name '*.log' -exec ls -l {} \;

対処: -exec のコマンドは \;(1 件ずつ実行)または +(まとめて実行)で必ず終端する。

症状: find / を実行すると権限エラーが大量に出る

原因: 一般ユーザーで読めないディレクトリ(/proc の一部や他ユーザー領域)を走査している

確認:

find / -name target.conf 2>/dev/null

対処: 2>/dev/null で標準エラーを捨てるか、検索範囲を /etc 等に絞る。システム全体を確実に探すなら sudo find を使う。

作業完了チェックリスト

  • [ ] 主要 FHS ディレクトリの用途を表で確認した
  • [ ] 共有可能/非共有・静的/可変の区分を理解した
  • [ ] find で名前・種類・サイズ・更新日時・権限・所有者の検索を試した
  • [ ] -exec {} \;-exec {} + の違いを確認した
  • [ ] locate 検索後に sudo updatedb で更新を反映した
  • [ ] which / whereis / type を使い分けた

まとめ

目的 コマンド / 場所 ポイント
設定ファイルの場所 /etc(静的・非共有) ホスト固有
可変データの場所 /var(ログ・スプール) 運用で変化
手動導入ソフト /usr/local パッケージ管理と分離
条件付き検索+処理 find -size/-mtime/-exec 実時間・最新・後処理可
名前の高速検索 locatesudo updatedb DB 参照・要更新
実行ファイルの場所 which / whereis / type 用途で使い分け

FHS はファイルの「正しい置き場所」を判断する地図、find / locate はその地図上で目的のファイルを探す道具。両方を押さえれば、未知のシステムでも設定やログを迷わず辿れる。

次に読む