UNIX/Linuxの部屋 コマンド:find ファイル名・タイムスタンプ・ファイルサイズなどを元に、ファイル・ディレクトリを検索する。


※空白区切りで AND 検索 (例:「ファイル 削除」)

コマンド find ファイル名・タイムスタンプ・ファイルサイズなどを元に、ファイル・ディレクトリを検索する。

UNIX/Linux の find コマンドは、ファイル名・タイムスタンプ・ファイルサイズ・オーナー・グループ・ファイルタイプなどを元に、ファイルやディレクトリを検索するコマンドである。AND・OR の組み合わせや正規表現が使えたり、検索だけではなくコマンドの実行も可能など、非常に強力なコマンドである。

基本的には
% find 検索開始ディレクトリ 検索条件 アクション
という書式で使う。FreeBSD・Linux など一部の find では、
% find /usr
と、検索開始ディレクトリのみを指定すると、コマンドとして -print が指定されたものとして動作する。また、Linux などの GNU find では
% find
と検索開始ディレクトリの省略も可能。この場合カレントディレクトリが検索開始ディレクトリとみなされる。

注意
find は、OS によって使用可能なオプションが大きく異なる。最も高機能な find は、Linux で使用されている GNU find であろう。*BSD の find も、GNU find の機能を積極的に取り込んでいる。一方、Solaris や HP-UX の find は、ここにあげたオプションの半分以上は使用できない。使っている OS のマニュアルでの確認を忘れずに。

検索開始ディレクトリ
検索を開始する起点のディレクトリを指定する
% find /foo/bar -type f -print
⇒ /foo/bar 以下の全ファイルの一覧を表示
% find . -type f -print
⇒ カレントディレクトリ以下の全ファイルの一覧を表示
検索開始ディレクトリは複数指定することも可能である。
% find /usr/local /usr/bin /usr/sbin -type f -print
⇒ /usr/local と /usr/bin と /usr/sbin 以下の全ファイルを表示

検索条件オプション ファイル名
-name file
検索するファイル名・ディレクトリ名を指定する。指定するファイル名は部分一致ではなく完全一致であることに注意しよう。
% find . -name foo.txt -print
→ 「foo.txt」というファイルまたはディレクトリを検索する。「foo.txt.bak」はヒットしない。
% find . -name mydir -print
→ 「mydir」というファイルまたはディレクトリを検索する。「mydir2」はヒットしない。
ワイルドカードとして *・?・[・] を使用することが可能だが、その場合は "" などで囲んだり、エスケープしよう。
% find . -name "*abc*"
→ 名前のどこかに "abc" を含むファイルまたはディレクトリを検索する。
% find . -name \*abc\*
→ \ でエスケープしてもよい。
ワイルドカードでは足りない複雑な条件の場合、より強力な -regex で正規表現で指定するとよい。

-name は、「そのエントリのみ」が検索対象であることに注意。カレントディレクトリ以下に
abc.txt
xxx/
xxx/abc.txt
abc/
abc/def.txt
というファイル・ディレクトリがあるとき、
% find . -name "*abc*"
とすると、abc.txt と abc/ と xxx/abc.txt はマッチするが、abc/def.txt はマッチしない。
-iname file
検索するファイル名を指定。大文字小文字を区別しない以外は -name と同じ。
-regex reg
パスを含むファイル名全体が正規表現 reg にマッチするものを検索する。-name と異なり、検索対象がパスも含むことに注意。また、「〜を含む」ではなく、「全体がマッチする」という条件であることにも注意。例えば
% find . -regex "abc"
は絶対にマッチしない。なぜなら、カレントディレクトリに abc というファイルがあった場合は「./abc」と出力されるが、これは -regex で指定した正規表現「abc」とマッチしないからである。この場合は
% find . -regex ".*abc.*"
としなければならない。
-iregex reg
大文字小文字を区別しない以外は、-regex と同じ。

検索条件オプション タイムスタンプ
-mtime [+-]n
mtime オプションを使うと、n日前に修正されたファイルを検索することができる。日数にプラスマイナスをつけることで、N日以前・N日以後・N日より前、などの条件をつけることができる。驚くことに、BSD の find と GNU の find で、mtime +N の意味が異なるようだ。要注意である。
-mtime 1 1日前 (24時間前〜現在) に修正されたファイル
-mtime 2 2日前 (48時間前〜24時間前) に修正されたファイル
(BSD find)-mtime +0 現在より前に修正されたファイル
(BSD find)-mtime +1 1日前 (24時間前) より前に修正されたファイル
(GNU find)-mtime +0 1日前 (24時間前) より前に修正されたファイル
(GNU find)-mtime +1 2日前 (48時間前) より前に修正されたファイル
-mtime -0 現在より後に修正されたファイル
-mtime -1 1日後 (24時間後より後) に修正されたファイル

UNIXのタイムスタンプ全般についてはタイムスタンプの項を参照。
-atime [+-]n
n日前にアクセスされたファイル。それ以外は mtime と同じ。
-ctime [+-]n
n日前にファイルステータスが変更されたファイル。それ以外は mtime と同じ。
-newer file
ファイル file よりタイムスタンプが新しいファイル・ディレクトリを検索。タイムスタンプ比較用ファイルをあらかじめ作成し、touch コマンドを使ってタイムスタンプを変更し、そのファイルと比較するとよい。

逆に、「〜より古い」という条件で検索したい場合は、条件の否定を使う。
% find . \! -newer file -print

検索条件オプション ユーザ・グループ
-user ユーザ名またはUID
指定のユーザが所有するファイル・ディレクトリ等
-group グループ名またはGID
指定のグループが所有するファイル・ディレクトリ等
-nouser
/etc/passwd に載っていない UID が所有するファイル・ディレクトリ等
-nogroup
/etc/group に載っていない GID が所有するファイル・ディレクトリ等
-nouser と -nogroup は、削除済のユーザ・グループが所有していたファイル・ディレクトリが残っていないかの確認に使う。
検索条件オプション 階層系
-maxdepth n
検索対象を n 階層に制限する。
% find / -maxdepth 0
/
⇒ 0 階層目 (指定した検索開始ディレクトリ) でストップ

% find / -maxdepth 1
/
/dev
/etc
(略)
⇒ 1 階層目でストップ。ただし 0階層目の / も表示されていることに注意。

% find / -maxdepth 2
/
/dev
/dev/network
(略)
/etc
/etc/defaults
(略)
⇒ 2 階層目でストップ。ただし 0・1階層目も表示されていることに注意。
-mindepth n
n 階層以内のファイル・ディレクトリを表示しない。上位のディレクトリを対象外にしたい場合に有用。
% find / -mindepth 1
/dev
/dev/network
/dev/geom.ctl
(略)
⇒ / が表示されていないことに注意

% find / -mindepth 2
/dev/network
/dev/geom.ctl
(略)
⇒ / と /dev が表示されていないことに注意

-mindepth は、-maxdepth と組み合わせると有用である。
% find /usr -maxdepth 1 -mindepth 1 -type d
⇒ /usr 直下にあるディレクトリのみを表示。
-prune
それ以上ディレクトリを降りない。特定のディレクトリ以下を除外する場合に有用。
% find . -prune -print
.
⇒ 単体で使用しても意味がない。
% find . -type d -name CVS -prune -o -print
⇒ CVS/ 以下を除外する。
% find /usr/* -type d -prune
⇒ /usr 直下にあるディレクトリのみを表示
実際は -prune はディレクトリ以外にも効果があるので、
% find . -name "*.txt" -prune -o -print
⇒ *.txt というファイルを除外する。
という使い方もできるが、これは
% find . \! -name "*.txt"
と同じである。
検索条件オプション ファイルサイズ・ファイルタイプ・i-node等
-inum inode 番号
指定の inode のファイルまたはディレクトリ。inode は ls -i で確認できる。inode はファイルシステムごとの通番のような番号なので、複数のファイルシステムにまたがった場合は同じ inode が存在する可能性があることに注意。

例えば、/・/usr・/home・/var という 4つのファイルシステムがマウントされている場合、
% find /usr -inum 100
であればファイルが 1つに特定できるが、
% find / -inum 100
とすると /・/usr・/home・/var それぞれの inode が 100 であるファイルが表示される可能性がある。
-size [+-]n[ckMG]
ブロックサイズまたはファイルサイズで検索。「-size 100」だとブロックサイズとみなし、「-size 100c」などと末尾に c をつけるとファイルサイズとみなす。サイズの前に「+」「-」を付けることで、N以上・N以下を指定できる。
% find . -size 100c
⇒ ファイルサイズがちょうど 100 バイトのファイル・ディレクトリを検索
% find . -size +100c
⇒ ファイルサイズが 101 バイト以上のファイル・ディレクトリを検索
% find . -size -100c
⇒ ファイルサイズが 99 バイト以下のファイル・ディレクトリを検索

% find . -size 4
⇒ ブロックサイズが 4 のファイル・ディレクトリを検索
% find . -size +4
⇒ ブロックサイズが 5 以上のファイル・ディレクトリを検索
% find . -size -4
⇒ ブロックサイズが 3 以下のファイル・ディレクトリを検索
各ファイルのブロックサイズは ls -s で参照できる。

また、GNU find では「-size 100k」「-size 100M」「-size 100G」とすることで、キロバイト・メガバイト・ギガバイトの指定ができる (1k=1024バイト、1M=1,048,576バイト、1G=1,073,741,824バイト)。

+ - について、以上なのか超なのか、以下なのか未満なのかは未調査。なぜか BSD も GNU も、find のマニュアルに + - について言及がない。
-type [ファイルタイプ] ファイルの種類
-type オプションに続けて以下のようなファイルタイプを指定することで、ファイルのみ・ディレクトリのみ、などと特定のファイルタイプのみを選択できる。また、! や -not を使うことで、特定のファイルタイプを除外する。
% find . -type f
→ ファイルのみを検索する。
% find . -type d
→ ディレクトリのみを検索する。
% find . -type f or -type l
→ ファイルまたはシンボリックリンクを検索する。
% find . \! -type d
→ ディレクトリのみ除外する。

ファイルタイプは以下のとおり。
b ブロックデバイス
c キャラクタデバイス
d ディレクトリ
f ファイル
l シンボリックリンク
p 名前付きパイプ
s ソケット (UNIX ドメインソケット)
D Door (Solaris のみ)

-empty
空のファイル、空のディレクトリの場合。具体的には
  • 「ファイルで、そのサイズがゼロ」
  • 「ディレクトリで、その下にファイル・ディレクトリ等がない」
のいずれかである。
条件の結合・否定などのオプション
-a または -and
検索条件を AND で結ぶ。
% find . -name abc -and -type d
⇒ abc という名前のディレクトリを検索
ただし、複数の検索条件を並べて書けば AND として扱われるので、上記コマンドは
% find . -name abc -type d
と同じ。
-o または -or
検索条件を OR で結ぶ。
% find . -name abc -or -type d
⇒ abc という名前のファイル・ディレクトリか、あるいはディレクトリを検索
! または -not
他の条件の前に付けて、条件を否定する。-not は一部の find でしか使えない。
% find . \! -name \*.txt -print
⇒ 拡張子が .txt で *ない* ファイル・ディレクトリ
% find . -not -newer target.txt -print
⇒ target.txt とタイムスタンプが同じか、あるいは古いファイル・ディレクトリ
アクション
-print 対象ファイル名を表示する。
-ls 対象ファイルを詳しく (ls -l と同じように) 表示する。
より正確に言うと、行頭に inode と使用ブロックサイズが表示されるため、ls -lis と同じである。
-exec 検索ファイルを引数としてコマンドを実行する。-exec の後にはコマンドを指定し、コマンドの終了を示すために最後に ";" で終端する。{} と書いた部分はそれぞれのファイル・ディレクトリ名に置換される。
% find dir/ -name \*.txt -exec chmod 644 {} \;
→ dir/ 以下の *.txt について chmod 644 を実行する。
";" はシェルに解釈させずに find コマンドに渡す必要があるので、上記のように \; と書くか、あるいは ";" などと書いてエスケープする必要がある。{} と \; の間にはスペースが必要であることに注意。
-ok -exec と同じだが、実行する際に確認を求める。
-delete 対象ファイル・ディレクトリを削除する。
% find dir/ -delete
→ dir 以下 (dir も含む) の全ファイル・ディレクトリを削除する。
% find dir/ -name \*.txt -delete
→ dir 以下から、拡張子 txt のファイルを削除する。

アクションの例を以下に示す。
% find / -name .cshrc -print
⇒ ルートディレクトリ以下の .cshrc を検索してフルパスを表示する
% find /usr/local -name file\* -ls
⇒ /usr/local 以下の file* を検索して詳細な情報を表示する
% find . -name \*~ -exec rm {} \;
⇒ カレントディレクトリ以下の *~ をリストアップして rm コマンドで削除する。
% find . -name \*~ -print -exec rm {} \;
⇒ コマンドは複数個指定できる。
% find . -name \*~ -exec ls {} \; -exec rm {} \;
⇒ (この例はあまり意味はないが) -exec を複数個指定してもよい。

Howto: Permission denied などのエラーを抑止するには
他ユーザのディレクトリを検索する場合、読み込み権限のないディレクトリは permission denied と表示され、出力が見にくくなる。csh・tcsh なら
% (find / -name hoge\* -print >/dev/tty ) >& /dev/null
とすることで、標準エラー出力のみを捨てることができる。sh・bash なら
% find / -name hoge\* -print 2>/dev/null
とすればよい。

Howto: 複数のディレクトリを起点として検索するには
以下のように複数のディレクトリを羅列すればよい。
% find /dir1 /dir2 /dir3 ....

Howto: 特定のファイル名・ディレクトリ名を除外するには
ファイル名やディレクトリ名が拡張子 bak、.svn、.DS_Store であった場合は除外するには下記のようにする。
% find dir/ ! -name \*.bak ! -name .svn ! -name .DS_Store

Howto: ファイル名について大文字小文字を区別せずに検索するには
-iname オプションを使うことで、file.txt にも FILE.TXT にもマッチする。正規表現を使いたい場合は -iregex を使う。
% find dir/ -iname file.txt

Howto: 改行コード CRLF を含むファイルを検索する
カレントディレクトリ以下から、改行コードが CRLF を含むファイル名の一覧を表示する例。
% find . -type f | xargs grep -lUPz '\r\n'
Linux・FreeBSD いずれも使えるはず。

locate コマンドの方が高速にファイルを検索できる。locate コマンドが使えるなら、まずそちらを使うべし。

ソースの中から文字列「hogehoge」を検索するには
% find . -name \*.c -exec grep hogehoge {} \;
とすればよいが、これでは *.c のファイルの数だけ grep コマンドが実行され、時間がかかる。そういう場合は
% find . -name \*.c -print | xargs grep hogehoge
とすればよい。ファイル名に空白などが含まれる場合は
% find . -name \*.c -print0 | xargs -0 grep hogehoge /dev/null
とするが (Linux・FreeBSD 等では使えるが、Solaris 等の find コマンドでは -print0 オプションは実装されていないと思われる)。
>> Solaris10オンラインマニュアル(man) Solaris10 find(1)
>> FreeBSDオンラインマニュアル(man) FreeBSD find(1)
>> Linuxオンラインマニュアル(man) Linux find(1)


頑張って書いたおすすめコンテンツ!