Linuxで再帰的にファイルを検索する方法|findとgrep -rを使いこなそう

Linux

Linuxで作業をしていると「サブディレクトリも含めてファイルを探したい」「設定ファイルの中からエラーの原因を探したい」と思う場面がよくあります。

こんな場面で必要になります

  • プロジェクト全体から特定のファイル名を探したい
  • ログファイルの中からエラーメッセージを検索したい
  • 設定ファイルから特定の設定項目を見つけたい
  • 古いファイルや大きなファイルを整理したい
  • ソースコードから特定の関数や変数を探したい

単純にlsコマンドを使うだけでは、現在のディレクトリしか見てくれません。

そこで必要になるのが再帰的にファイルを検索するコマンドです。

この記事では、Linuxで再帰的にファイルを検索するための代表的なコマンドfindgrep -rを、初心者にもわかりやすい例とともに詳しく解説します。

これを読めば複雑なディレクトリ構造の中からでも目的のファイルや情報を効率的に見つけられるようになりますよ!

スポンサーリンク

再帰的検索とは?

基本概念

再帰的検索とは、指定したディレクトリだけでなく、その中のサブディレクトリ、さらにその中のサブディレクトリと、階層の深い部分まで自動的に検索することです。

通常の検索(非再帰的)

project/
├── file1.txt    ← 検索される
├── file2.txt    ← 検索される
└── subfolder/
    ├── file3.txt    ← 検索されない
    └── deep/
        └── file4.txt    ← 検索されない

再帰的検索

project/
├── file1.txt    ← 検索される
├── file2.txt    ← 検索される
└── subfolder/
    ├── file3.txt    ← 検索される
    └── deep/
        └── file4.txt    ← 検索される

なぜ再帰的検索が必要?

現実的なディレクトリ構造

/var/log/
├── apache2/
│   ├── access.log
│   ├── error.log
│   └── sites/
│       └── example.log
├── nginx/
│   ├── access.log
│   └── error.log
└── mysql/
    ├── error.log
    └── slow.log

この構造で「error.log」を全て探したい場合、各ディレクトリを手動で確認するのは非効率的です。再帰的検索なら一発で見つけられます。

findコマンドで再帰的にファイルを探す

findの基本的な仕組み

findコマンドはデフォルトで再帰的に動作します。指定したディレクトリ以下のすべてのサブディレクトリを自動的に探索します。

基本構文

find [検索開始ディレクトリ] [検索条件] [アクション]

ファイル名による検索

基本的なファイル名検索

# カレントディレクトリ以下の.logファイルを探す
find . -name "*.log"

# /var/log以下の.logファイルを探す
find /var/log -name "*.log"

# 特定のファイル名を探す
find /home -name "config.txt"

実行例と出力

$ find . -name "*.log"
./apache2/access.log
./apache2/error.log
./nginx/access.log
./nginx/error.log
./mysql/error.log

大文字・小文字を無視する検索

# 大文字小文字を区別しない
find . -iname "*.jpg"

# image.JPG、photo.jpg、Picture.JPEG などがすべて検索される

部分一致での検索

# ファイル名に"config"を含むファイル
find /etc -name "*config*"

# ファイル名が"test"で始まるファイル
find . -name "test*"

# ファイル名が".conf"で終わるファイル
find /etc -name "*.conf"

ファイルタイプによる検索

ファイルタイプの指定

# 通常ファイルのみ
find . -type f -name "*.txt"

# ディレクトリのみ
find . -type d -name "log*"

# シンボリックリンクのみ
find . -type l

# 実行可能ファイルのみ
find /usr/bin -type f -executable

ファイルタイプの種類

  • f:通常ファイル
  • d:ディレクトリ
  • l:シンボリックリンク
  • c:キャラクタデバイス
  • b:ブロックデバイス
  • p:名前付きパイプ
  • s:ソケット

日付やサイズによる検索

更新日時による検索

# 30日以上前に変更されたファイル
find . -mtime +30

# 7日以内に変更されたファイル
find . -mtime -7

# ちょうど3日前に変更されたファイル
find . -mtime 3

# 1時間以内に変更されたファイル
find . -mmin -60

ファイルサイズによる検索

# 1MB以上のファイル
find . -size +1M

# 100KB以下のファイル
find . -size -100k

# ちょうど0バイト(空ファイル)
find . -size 0

# 1GB以上のファイル
find . -size +1G

サイズ単位

  • c:バイト
  • k:キロバイト
  • M:メガバイト
  • G:ギガバイト

パーミッションによる検索

実行可能ファイルの検索

# すべてのユーザーが実行可能
find . -perm -111

# 所有者が実行可能
find . -perm -100

# setuidが設定されたファイル
find /usr -perm -4000

特定のパーミッションを持つファイル

# パーミッションが755のファイル
find . -perm 755

# パーミッションが777のファイル(セキュリティチェック)
find . -perm 777

複数条件の組み合わせ

AND条件(-aまたは省略)

# .confファイルかつ7日以内に変更
find /etc -name "*.conf" -mtime -7

# 1MB以上かつ30日以上古いファイル
find . -size +1M -mtime +30

OR条件(-o)

# .logファイルまたは.txtファイル
find . \( -name "*.log" -o -name "*.txt" \)

# .confファイルまたは.yamlファイル
find . -name "*.conf" -o -name "*.yaml"

NOT条件(!)

# .gitディレクトリ以外
find . ! -name ".git"

# 隠しファイル以外
find . ! -name ".*"

grepコマンドで再帰的に内容を検索

grep -rの基本

grepはファイルの中から文字列を探すコマンドです。-r--recursive)オプションを付けると、サブディレクトリまで再帰的に検索します。

基本構文

grep -r [オプション] "検索文字列" [検索ディレクトリ]

基本的な文字列検索

単純な文字列検索

# /etc以下で"password"を含む行を検索
grep -r "password" /etc

# カレントディレクトリ以下で"error"を検索
grep -r "error" .

# 大文字小文字を無視して検索
grep -ri "error" /var/log

実行例と出力

$ grep -r "listen" /etc/nginx
/etc/nginx/nginx.conf:    listen 80;
/etc/nginx/sites-available/default:    listen 80 default_server;
/etc/nginx/sites-available/default:    listen [::]:80 default_server;

便利なオプション

行番号を表示(-n)

grep -rn "error" /var/log
# 出力例:
# /var/log/apache2/error.log:245:Error connecting to database

ファイル名のみ表示(-l)

# エラーを含むファイルの一覧のみ
grep -rl "error" /var/log

# 出力例:
# /var/log/apache2/error.log
# /var/log/nginx/error.log

マッチしないファイル名を表示(-L)

# "TODO"を含まないファイルの一覧
grep -rL "TODO" ./src

マッチした行数をカウント(-c)

# 各ファイルでのマッチ行数
grep -rc "error" /var/log

# 出力例:
# /var/log/apache2/error.log:25
# /var/log/nginx/error.log:3

前後の行も表示

# マッチした行の前後2行も表示
grep -r -A 2 -B 2 "error" /var/log

# マッチした行の前後5行を表示
grep -r -C 5 "error" /var/log

ファイルの絞り込み

特定の拡張子のみ検索

# .confファイルのみ対象
grep -r --include="*.conf" "listen" /etc

# .phpファイルのみ対象
grep -r --include="*.php" "mysql_connect" ./

# 複数の拡張子
grep -r --include="*.{php,html,js}" "function" ./

特定のファイルを除外

# .gitディレクトリを除外
grep -r --exclude-dir=".git" "TODO" ./

# ログファイルを除外
grep -r --exclude="*.log" "error" ./

# 複数のパターンを除外
grep -r --exclude-dir="{.git,node_modules}" "function" ./

正規表現での検索

基本的な正規表現

# 行の始まりが"Error"
grep -r "^Error" /var/log

# 行の終わりが"failed"
grep -r "failed$" /var/log

# IPアドレスっぽいパターン
grep -r "[0-9]\+\.[0-9]\+\.[0-9]\+\.[0-9]\+" /var/log

拡張正規表現(-E)

# メールアドレスのパターン
grep -rE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" ./

# HTTPステータスコード(4xxまたは5xx)
grep -rE " [45][0-9]{2} " /var/log/apache2/

findとgrepを組み合わせた高度な検索

exec オプションを使った組み合わせ

基本的な組み合わせ

# .phpファイルの中から"mysqli"を検索
find . -name "*.php" -exec grep "mysqli" {} \;

# より詳細な情報付きで検索
find . -name "*.php" -exec grep -Hn "mysqli" {} \;

-H オプションの説明

  • -H:ファイル名を常に表示
  • -n:行番号を表示

xargs を使った効率的な検索

基本的なxargsの使用

# 基本形
find . -name "*.log" | xargs grep "error"

# ファイル名に空白がある場合の安全な方法
find . -name "*.log" -print0 | xargs -0 grep "error"

xargsの利点

  • 処理速度が速い
  • メモリ使用量が少ない
  • 大量のファイルを効率的に処理

実用的な組み合わせ例

設定ファイルからポート番号を探す

find /etc -name "*.conf" -exec grep -Hn "port\|Port\|PORT" {} \;

ソースコードからTODOコメントを探す

find ./src -name "*.{js,php,py}" | xargs grep -n "TODO\|FIXME\|XXX"

大きなログファイルからエラーを探す

find /var/log -name "*.log" -size +10M -exec grep -l "ERROR\|FATAL" {} \;

最近変更されたファイルから特定の文字列を探す

find . -name "*.php" -mtime -7 | xargs grep -l "password"

パフォーマンスの最適化

検索速度を上げるコツ

不要なディレクトリを除外

# .gitディレクトリを除外
find . -path "./.git" -prune -o -name "*.php" -print

# 複数のディレクトリを除外
find . \( -path "./.git" -o -path "./node_modules" \) -prune -o -name "*.js" -print

locate を使った高速検索

# データベースを使った高速検索(事前に updatedb が必要)
locate "*.conf" | grep nginx

# データベースの更新
sudo updatedb

ripgrep(rg)を使った高速検索

# ripgrepがインストールされている場合
rg "error" /var/log

# デフォルトで多くの除外設定が適用される
rg "function" ./src

メモリ使用量を抑える

一度に処理するファイル数を制限

find . -name "*.log" | head -100 | xargs grep "error"

大きなファイルを分割して処理

find . -name "*.log" -size +100M -exec sh -c 'split -l 10000 "$1" "/tmp/$(basename "$1")_"' _ {} \;

実用的な活用例

システム管理での活用

ログファイルの分析

# エラーログの集計
find /var/log -name "*.log" | xargs grep -c "ERROR" | sort -t: -k2 -nr

# 最近のエラーを時系列で確認
find /var/log -name "*.log" -mtime -1 | xargs grep "ERROR" | sort

設定ファイルの管理

# 特定のIPアドレスが設定されている箇所を探す
find /etc -name "*.conf" | xargs grep -n "192.168.1.100"

# SSL証明書のパスを探す
find /etc -name "*.conf" | xargs grep -i "ssl.*cert"

セキュリティチェック

# パスワードがハードコードされていないかチェック
find ./src -name "*.php" | xargs grep -i "password.*=" | grep -v "\$"

# setuidファイルの確認
find /usr -perm -4000 -ls

開発での活用

コードの品質チェック

# デバッグコードの残存チェック
find ./src -name "*.js" | xargs grep -n "console.log\|debugger"

# 未使用の変数を探す
find ./src -name "*.py" | xargs grep -n "^[[:space:]]*[a-zA-Z_][a-zA-Z0-9_]*[[:space:]]*="

依存関係の調査

# 特定のライブラリの使用箇所
find ./src -name "*.php" | xargs grep -n "use.*Symfony"

# 外部APIの呼び出し箇所
find ./src -name "*.js" | xargs grep -n "fetch\|axios\|ajax"

トラブルシューティング

よくある問題と対処法

Q:Permission denied エラーが出る A:権限のないディレクトリにアクセスしている場合

# エラーを無視して続行
find /var -name "*.log" 2>/dev/null

# sudo権限で実行
sudo find /var -name "*.log"

Q:検索が遅すぎる A:以下の最適化を試してください

# 不要なディレクトリを除外
find . -path "./node_modules" -prune -o -name "*.js" -print

# ファイルタイプを限定
find . -type f -name "*.txt"

# locate コマンドの使用を検討
locate "pattern"

Q:ファイル名に空白がある場合のエラー A:適切なオプションを使用してください

# 安全な方法
find . -name "*.txt" -print0 | xargs -0 grep "pattern"

# または -exec を使用
find . -name "*.txt" -exec grep "pattern" {} \;

Q:結果が多すぎて見きれない A:結果を絞り込んでください

# ページ単位で表示
find . -name "*.log" | less

# 件数を制限
find . -name "*.log" | head -20

# ファイルサイズで絞り込み
find . -name "*.log" -size +1M

よくある質問

Q:findとlocateの違いは?

A:以下の違いがあります

  • find:リアルタイム検索、条件が豊富、やや遅い
  • locate:データベース検索、高速、事前のインデックス更新が必要

Q:grepとackやripgrepの違いは?

A:機能面での違い

  • grep:標準コマンド、基本的な機能
  • ack/ag/rg:プログラマー向け、高速、除外設定が豊富

Q:再帰的検索でシンボリックリンクは追跡される?

A:コマンドによって異なります

# find:デフォルトでは追跡しない
find . -follow -name "*.txt"  # 追跡する場合

# grep:デフォルトでは追跡しない
grep -r --dereference-recursive "pattern" .  # 追跡する場合

まとめ:効率的なファイル検索をマスターしよう

この記事のポイント

目的コマンド特徴
ファイル名で検索find . -name "*.log"属性や日付でも絞り込み可能
ファイル内容を検索grep -r "error" .文字列パターンでの検索
組み合わせ検索find . -name "*.php" | xargs grep "function"柔軟で強力な検索
高速検索locate "pattern"事前インデックスが必要

使い分けのガイド

  • ファイル名・属性重視find コマンド
  • 内容重視grep -r コマンド
  • 複雑な条件find + grep の組み合わせ
  • 高速性重視locateripgrep

効率化のコツ

  • 不要なディレクトリは除外する
  • ファイルタイプを限定する
  • 適切なツールを選択する
  • 結果を絞り込む条件を工夫する

安全な使用のために

  • バックアップを取ってから変更作業
  • 権限エラーを適切に処理
  • ファイル名の空白に注意
  • 大量処理時はテストを先に実行

Linuxで再帰的にファイルを検索する技術をマスターすれば、ファイル名や属性で探すならfind、ファイルの中身を探すならgrep -r、さらに複雑な条件なら両者を組み合わせることで、数千・数万ファイルがある環境でもスムーズに目的の情報を見つけられます。

ぜひ日頃のファイル管理やトラブルシューティング、システム管理に役立ててみてください。

コメント

タイトルとURLをコピーしました