Linuxのfindコマンド:名前、サイズ、日時でファイルを探す例
find はディレクトリツリーをたどり、条件に合うファイルを選びます。find /path -name '*.log' は名前で、-type f はファイルのみ、-size +100M は100 MB 超、-mtime -7 は1週間以内に変更されたものを探します。条件は組み合わせられ、見つかったファイルには -exec や -delete で操作するか、xargs にリストを渡せます。
find はディレクトリツリーをたどり、名前、種類、サイズ、更新日時、所有者、権限などの条件でファイルを探します。基本の形は find [検索開始位置] [条件] [操作] です。以下では、設定ファイルを見つける、古いログを消す、ディスク容量を圧迫しているファイルを特定するといった日常の作業向けに、find linux の例をまとめます。
find コマンドの構文
find /var/log -type f -name '*.log' -mtime +30 -print
各部分の意味は次のとおりです。
/var/log:検索を始める場所。複数のディレクトリを続けて指定することも、.(カレントディレクトリ)を指定することもできます。パスを省略すると GNU find はカレントディレクトリを検索します。-type f -name '*.log' -mtime +30:条件(マニュアルではテストと呼ばれます)。条件同士は既定で「AND」で結ばれます。-print:操作。パスを表示します。ほかに操作がなければ自動的に付きます。
find は再帰的にすべてのサブディレクトリをたどります。一般ユーザーでシステムのパスを検索すると、Permission denied という行が大量に出ることがあります。エラーの出力を捨てて抑えられます。
find / -name 'nginx.conf' 2>/dev/null
名前による検索:-name と -iname
-name はファイル名(パスを除く部分)だけをパターンと比較します。パターンでは *(任意の文字列)、?(任意の1文字)、[abc](指定した文字のどれか1つ)が使えます。
# 名前が完全に一致するもの
find /etc -name 'hosts'
# .conf で終わるすべてのファイル
find /etc -name '*.conf'
# 大文字小文字を区別しない:README.md, readme.MD, Readme.md
find ~/projects -iname 'readme.md'
# report_1.csv ~ report_9.csv
find . -name 'report_?.csv'
パターンは必ず引用符で囲んでください。囲まないと、シェルがカレントディレクトリのファイル名で *.conf を展開してしまい、find にはパターンではなくファイル名の一覧が渡されます。その結果、予期しない動作になるか、paths must precede expression というエラーで止まります。
パスによる検索:-path と -regex
ディレクトリも条件にしたい場合は -path を使います。こちらは完全なパス全体をパターンと比較します。
# src ディレクトリの中にある .js ファイルだけ
find . -path '*/src/*' -name '*.js'
より複雑なパターンには -regex(これも完全なパスに対する正規表現)を使います。大文字小文字を区別しない場合は -iregex です。
find . -regextype posix-extended -regex '.*\.(jpg|jpeg|png)$'
ディレクトリを除外する
たとえば node_modules や .git の中に入らないようにするには、-prune を使います。
find . -path ./node_modules -prune -o -name '*.js' -print
意味は「パスが ./node_modules なら中に入らない。そうでなければ(-o)、*.js を表示する」です。最後の -print は必須です。付けないと、除外したディレクトリ自体も出力に含まれてしまいます。よりシンプルですが遅くなる方法は -not -path '*/node_modules/*' です。こちらはディレクトリを最後まで走査したうえで、結果だけを絞ります。
種類による検索:-type
| 指定 | 検索対象 |
|---|---|
-type f | 通常のファイル |
-type d | ディレクトリ |
-type l | シンボリックリンク |
-type s | ソケット |
-type p | 名前付きパイプ(FIFO) |
# logs という名前のディレクトリだけ
find / -type d -name 'logs' 2>/dev/null
# 空のファイルと空のディレクトリ
find . -type f -empty
find . -type d -empty
# 壊れたシンボリックリンク
find . -xtype l
サイズによる検索:-size
-size は数値に単位の接尾辞を付けて指定します。c はバイト、k はキロバイト、M はメガバイト、G はギガバイトです。+ は「より大きい」、- は「より小さい」、符号なしは「ちょうど」を意味します。
# システム全体で 100 MB を超えるファイル
find / -type f -size +100M 2>/dev/null
# 10 MB 以上 50 MB 未満
find . -type f -size +10M -size -50M
# 1 KB 未満
find . -type f -size -1k
注意点があります。サイズは単位に合わせて切り上げられます。そのため -size -1M が見つけるのは空のファイルだけです。空でないファイルは切り上げにより「少なくとも 1 MB」になるからです。厳密な境界が必要なら、より小さい単位を使ってください。例:-size -1024k。
ディスク容量を占めているもの
ls と sort を組み合わせると、最も大きいファイルが分かります。
find /var -type f -size +50M -exec ls -lh {} + 2>/dev/null | sort -k5 -rh | head
-rw-r----- 1 syslog adm 1.2G Oct 14 09:12 /var/log/syslog.1
-rw-r--r-- 1 root root 412M Oct 10 03:00 /var/backups/db.sql.gz
-rw-r----- 1 root adm 96M Oct 14 09:15 /var/log/nginx/access.log
ディレクトリ全体の大きさを調べるには du -sh が便利です。find は、深い場所にある巨大な1つのファイルが容量を使っている場合に役立ちます。
日時による検索:-mtime、-mmin、-newer
ファイルには3つのタイムスタンプがあり、find はそれぞれで絞り込めます。
| 条件 | タイムスタンプ | 単位 |
|---|---|---|
-mtime / -mmin | 内容の変更 | 日 / 分 |
-atime / -amin | 最後の読み取り | 日 / 分 |
-ctime / -cmin | メタデータの変更(権限、所有者、名前) | 日 / 分 |
符号の意味はサイズの場合と同じです。-mtime -7 は 7 日以内に変更されたもの、-mtime +30 は 30 日より前に変更されたものです。
# 過去 1 週間に変更されたファイル
find ~/projects -type f -mtime -7
# 30 日より古いログ
find /var/log -type f -name '*.log' -mtime +30
# 過去 15 分に変更された設定ファイル
find /etc -type f -mmin -15
日数は24時間単位の整数で数えられ、端数は切り捨てられます。そのため -mtime +1 が見つけるのは 24 時間ではなく 48 時間より前のファイルです。これはよくある落とし穴です。正確に指定したい場合は分単位を使います。例:-mmin +1440。
別のファイルや日付より新しいファイル
# deploy.lock が変更された後に変更されたファイル
find . -type f -newer deploy.lock
# 特定の日付以降に変更されたファイル(GNU find)
find . -type f -newermt '2026-10-01'
# 期間を指定
find . -type f -newermt '2026-10-01' ! -newermt '2026-10-08'
所有者と権限による検索
# alice が所有するファイル
find /home -user alice
# 所有者が存在しないファイル(ユーザー削除後など)
find / -nouser 2>/dev/null
# 権限がちょうど 777 のファイル
find /var/www -type f -perm 777
# すべてのユーザーが書き込めるファイル
find /var/www -perm -o=w
# SUID ビットが付いたファイル(セキュリティ監査に有用)
find / -perm -4000 -type f 2>/dev/null
-perm には3つの形式があります。符号なしは権限が完全に一致すること、- は指定したビットがすべて立っていること、/ は指定したビットのどれか1つが立っていることを意味します。
条件の論理:AND、OR、NOT
条件は既定で「AND」で結ばれます。「OR」には -o、否定には ! または -not を使います。グループ化には括弧を使いますが、シェルから守るためにエスケープが必要です。
# jpg または png の画像
find . -type f \( -name '*.jpg' -o -name '*.png' \)
# .tmp 以外のすべて
find . -type f ! -name '*.tmp'
括弧がないと、-type f は「OR」で結ばれた組の最初の条件にしか効かず、名前が *.png のディレクトリも結果に入ってしまいます。\( と \) の前後には空白が必要です。
検索の深さ:-maxdepth と -mindepth
# カレントディレクトリのみ。下位のディレクトリは含めない
find . -maxdepth 1 -type f -name '*.sh'
# 2 階層目以降だけ
find . -mindepth 2 -name '*.md'
# 別のファイルシステムに入らない
find / -xdev -type f -size +1G
-maxdepth はパスの直後、ほかの条件の前に置いてください。後ろに置くと GNU find が警告を出します。-xdev は / から検索するときに役立ちます。これを付けると find は /proc、ネットワークドライブ、マウントされたディスクに入りません。
見つかったものへの操作:-exec、-delete、xargs
-exec:各ファイルに対してコマンドを実行する
{} の位置に find がファイルのパスを入れます。コマンドは \; または + で終わります。
# ファイルごとに 1 回ずつ実行
find . -name '*.sh' -exec chmod +x {} \;
# すべてのファイルを 1 回のリストで渡す(高速)
find . -name '*.log' -exec gzip {} +
# ファイルごとに確認を求める
find . -name '*.bak' -ok rm {} \;
+ を使うと、パスがまとめて渡されるため、コマンドの起動回数が大幅に減ります。数千のファイルを扱うときは数倍速くなります。\; は、コマンドが 1 ファイルずつしか受け付けない場合や、{} を末尾に置けない場合に使います。
-delete:見つかったものを削除する
# 削除対象を先に確認する
find /tmp/build -type f -name '*.o' -mtime +7
# 問題なければ削除する
find /tmp/build -type f -name '*.o' -mtime +7 -delete
削除の前には、必ず -delete を付けずに実行して一覧を確認してください。また -delete は必ず最後に置きます。find は式を左から右へ評価するので、find . -delete -name '*.o' はディレクトリ内のすべてを削除してから名前を確認してしまいます。
find と xargs
ファイルのリストを別のプログラムに渡す定番の方法は xargs です。名前に空白が含まれていても壊れないように、区切りにナル文字を使います。
find . -type f -name '*.txt' -print0 | xargs -0 wc -l
xargs の -P オプションを使うと、並列で処理できます。
find ./images -name '*.png' -print0 | xargs -0 -P 4 -n 10 optipng
find と grep:ファイルの中身を検索する
find はファイルを探しますが、中身は検索しません。選んだファイルの中から文字列を探すには、その結果を grep に渡します。
# 設定ファイルの中で listen 8080 を探す
find /etc/nginx -type f -name '*.conf' -exec grep -Hn 'listen 8080' {} +
/etc/nginx/sites-enabled/app.conf:4: listen 8080;
-H はファイル名、-n は行番号を表示します。一致したファイル名だけを表示するには grep -l を使います。拡張子で絞るだけでよければ、grep 単体で十分です。例:grep -rn --include='*.conf' 'listen 8080' /etc/nginx。
出力形式を指定する:-printf
GNU find はパスだけでなく、任意の形式で情報を出力できます。例えばサイズ、日付、名前などです。
find . -maxdepth 1 -type f -printf '%s\t%TY-%Tm-%Td\t%p\n' | sort -n
%s はバイト単位のサイズ、%T... は更新日時の各部分、%p はパスです。スクリプトでは ls の出力を解析せずに済むので便利です。
毎日使える find linux の例の一覧
| 作業 | コマンド |
|---|---|
| 名前でファイルを探す | find / -name 'file.txt' 2>/dev/null |
| 大文字小文字を区別しない | find . -iname '*.jpg' |
| ディレクトリだけ | find . -type d -name 'cache' |
| 1 GB を超えるファイル | find / -xdev -type f -size +1G |
| 1 日以内に変更されたもの | find . -type f -mtime -1 |
| 1 時間以内に変更されたもの | find . -type f -mmin -60 |
| 30 日より古いログを削除 | find /var/log/app -name '*.log' -mtime +30 -delete |
| 空のディレクトリ | find . -type d -empty |
| すべてのディレクトリの権限を変更 | find . -type d -exec chmod 755 {} + |
| ファイルの中の文字列 | find . -name '*.py' -exec grep -l 'TODO' {} + |
| ファイル数を数える | find . -type f | wc -l |
よくあるミス
- パターンを引用符で囲まない。
find . -name *.logは、カレントディレクトリに.logで終わるファイルが2つ以上あると壊れます。'*.log'と書いてください。 - Permission denied が大量に出る。
2>/dev/nullを付けるか、ディスク全体が本当に必要ならsudoで実行してください。 -deleteの位置が違う。必ず最後に置き、その前に削除を伴わないテスト実行を行ってください。- パイプラインで空白を含む名前が壊れる。
find ... | xargs rmは「My File.txt」を2つの引数に分けてしまいます。-print0とxargs -0、または-execを使ってください。 -mtimeで正確な日数を期待する。正確な間隔が必要なら-mminまたは-newermtを使ってください。
まとめ
find はファイルシステムを検索する汎用ツールです。パスを指定し、名前、種類、サイズ、日時、権限で条件を決め、最後に操作を指定します。-name、-type、-size、-mtime、-exec ... + の5つを押さえておけば、ほとんどの作業が1行で済みます。ここで紹介した find linux の例は、実際のターミナルで試してみてください。find と grep、sed、awk の組み合わせは、Linux コースのテキスト処理の講義で実践しながら解説しています。
よくある質問
find と locate の違いは何ですか?
locate は事前に作成された名前のデータベースを検索するので瞬時に結果が出ますが、updatedb の最終実行後に作成されたファイルは見つかりません。find はディスクを実際に走査し、サイズ、日時、権限による絞り込みができます。
ファイル名ではなく中身からファイルを探すには?
find 自体は中身を読みません。grep -rn '文字列' /パス を使うか、find . -name '*.conf' -exec grep -l '文字列' {} + を組み合わせてください。
ルートディレクトリから find を実行すると遅いのはなぜですか?
/proc、/sys、マウントされたディスクを含むすべてのディレクトリを走査するからです。検索範囲を特定のディレクトリに絞り、-xdev と -maxdepth を付けるか、-prune で不要な部分を除外してください。
find の結果を日時順に並べることはできますか?
はい。find . -type f -printf '%T@ %p\n' | sort -n で古いものから新しい順に表示されます。%T@ は更新時刻を epoch からの秒数で示します。
空のディレクトリを探して削除するには?
find . -type d -empty -delete で、空のディレクトリを削除できます。内部のファイルを消した結果として空になったディレクトリも対象になります。先に -delete なしで実行して一覧を確認してください。