Linuxでディレクトリを再帰的に検索する方法とその応用

Linuxでディレクトリを再帰的に検索する方法とその応用の実務上の結論は「pathや属性はfind、内容はgrep -rを使い分けます。root、type、depth、mount境界、除外directoryを先に固定し、初回は表示だけにします。」です。recursive searchはroot、symlink追跡、mount境界、名前検索か内容検索かを明示します。0件と走査未完了を区別し、検索結果をそのまま削除commandへ渡しません。

目次

検索rootと越えてよい境界

名前やmetadataでentryを探す中心はfind、file内容を再帰検索する中心はgrep -rです。検索root、file type、depth、別filesystem、symbolic link追跡、除外directoryを先に定義します。/全体を既定対象にするとpermission error、pseudo filesystem、remote mount、巨大I/Oへ広がるため、最小の既知rootから開始します。

findの既定は通常symbolic linkを追わない-Pで、-Lはloopや参照先拡大へ注意します。-xdevで別filesystemを越えず、-pruneは式の優先順位と-oを括弧付きで確認します。file名を後続へ渡すときは-print0とNUL対応consumerを使い、空白や改行を含む名前をline単位で壊しません。

検索root・symlink・mount境界を閉じる

  • 検索rootと目的を明文化する
  • file名、属性、内容のどれを探すか決める
  • symlinkとmount境界の扱いを決める
  • 除外directoryとpermission errorを記録する

rootのreal pathが想定外、-Lで循環linkが生じる、別filesystemへ越える可能性がある場合は実行前に停止します。最小treeで括弧と-pruneの評価順を確認してから本番式へ移します。

findの式とgrepの内容検索を使い分ける

file名を再帰検索

find ./project -type f -name '*.yaml' -print

wildcardをquoteし、現在treeを走査します。

特定directoryを除外

find ./project -path './project/.git' -prune -o -type f -name '*.md' -print

-pruneと-oの評価順をsample treeで確認します。

mount境界を越えない

find /var -xdev -type f -name '*.log' -print

別filesystemを含めない理由を作業記録へ残します。

内容を対象拡張子だけ検索

grep -rnF --include='*.conf' --exclude-dir='.git' -- 'listen=' ./project

file名検索ではなくline内容検索として使います。

特殊file名をNUL区切りで出す

find ./project -type f -print0 | xargs -0 -r stat --format='%F %s %n' --

spaceやnewlineを含むpathの引数境界を保持します。

find式・prune・NUL区切り

findはstarting pointからtreeをwalkし、expressionを左から評価します。grep -rは各text file内容のpattern一致を探します。-rと-Rではsymbolic link追跡が異なる実装があり、findの既定もlinkをfollowしません。permission errorは0件とは別です。

findの結果は走査中のsnapshot保証ではなく、途中で追加・削除・renameされたentryが混ざる可能性があります。Permission deniedを除外済みと同じにせず、stdout、stderr、status、未走査pathを分けます。grep -rではmatchなし1とerror2があり、binary、encoding、line単位という制約も名前検索とは別です。

shellがfindへ渡す前にglobを展開する誤り、-pruneの括弧不足、-Lでのloop、network mount混入、newline入りfile名、途中削除をtestします。検索結果が0件でもroot誤りや権限不足かもしれません。errorを2>/dev/nullで隠して完全一覧と呼ばず、想定したdirectory数と未走査数を照合します。

0件・permission error・prune誤りを切り分ける

  • file名検索と内容検索を混同する
  • wildcardをshellに先に展開させる
  • symlink loopやmount越境を見落とす
  • permission deniedを一致なしとして集計する
  • newline入りfile名をline区切りで渡す

0件でもstatus 0になり得る一方、permission errorを含む部分結果もstdoutへ残ります。件数だけで成功にせずstderrを保存し、除外directoryへ誤って入った場合は式を修正して最初から再走査します。

-deleteなしの候補列挙で停止する

root /から無制限に再帰せず、pseudo filesystem、network mount、大規模cacheを除外します。最初は-print/-print0またはgrep表示だけにし、-delete、-execの変更を混ぜません。負荷上限、timeout、停止条件を用意します。

検索例へ-deleteや広い-execを混ぜません。見つかった結果を変更する処理は、候補をfileへ固定してreviewし、件数上限、owner、backup、rollbackを別段階で確認します。production rootへのrecursive scanはI/Oとmetadata serverへ負荷を掛けるため、時間帯、timeout、remote mount除外を管理者と決めます。

再帰検索を安全にtestする

nested、excluded、symlink、別mount、read不可、特殊file名を含むsample treeで期待一覧を作ります。find/grepのstdout、stderr、終了code、対象件数、実行時間を比較し、原本hashが不変か確認します。

通常file、hidden file、深いtree、除外directory、別mount候補、symbolic link loop、space/newlineを含む名前をfixtureにします。-type、-maxdepth、-xdev、-prune、-print0の期待集合をNUL安全な比較で検証します。走査中変更も再現し、結果が一貫しない場合を警告へできるか確認します。

定期jobではrootの絶対path、許可するfilesystem、最大depth、最大件数、timeoutを設定し、結果はNULまたは構造化形式で扱います。前回との差分を取るならdevice/inodeとmtimeも保存します。locateやindexerは高速でもindex時刻と対象範囲が異なるため、即時性が必要な確認と同じ成功条件にしません。

候補表示から変更workflowへ境界を引く

filename/metadata条件はfind、内容の単純line検索はgrep -r、repository内ならignore規則を理解する専用search、巨大基盤ならindex serviceを選びます。検索の目的が候補表示から削除・権限変更へ変わった時点で処理を止め、固定した対象listと承認を使う別workflowへ移します。

directoryだけを再帰検索するならfindの-type dを明示し、名前条件より前後の論理結合を括弧で確認します。除外directoryには-pruneを使いますが、式の左側へ置く順序を誤ると除外先も走査されるため、小さなtreeで対象pathを保存してから本番へ広げます。symlinkを辿る-Lはloopや別filesystemへの越境を招き得るので既定の-Pを基準にし、必要な場合だけ-xdevや深さ上限と組み合わせます。

合格は空root、除外tree、symlink loop、permission不可fixtureで候補集合と走査statusが期待どおりになることです。不完全runは候補を利用せず、式と境界を直して再検索します。

公式情報・参考資料

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次