ファイル探しのプロ、findコマンドを使いこなす

findは、指定したディレクトリから検索条件にマッチするファイルやディレクトリを検索するコマンドです。

頻繁に利用することになるし、試験にも出るので基本だけでも押さえておきたい重要コマンドです。

基本書式は、

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

です。

検索ディレクトリ

findコマンドでは検索ディレクトリは必須です。

自分のホームディレクトリを検索する場合は、

find ~

カレントディレクトリを指定する場合は、

find . 

同様にルートディレクトリの場合は、

find /

になります。

オプション

なお、オプションを指定する場合は、

find [検索ディレクトリ] [オプション] [条件式] [アクション]

のような書式になります。代表的なオプションは以下の通り。

オプション内容
-maxdepth 数値検索するサブディレクトリ階層を数値で指定。0の場合は当該ディレクトリのみを検索
-mindepth 数値検索するサブディレクトリ階層を数値で指定。1の場合は数値分下の階層から検索

エスパくん

LinuC認定本でオプションに関する記述があるのは、合格教本とスピードマスターだけで、いずれも-maxdepthが取り上げられていました。

条件式

条件式では、名前、種類、サイズ、更新時間、パーミッションなどの条件が指定できます。

条件式内容
-name 名前ファイルやディレクトリ名で検索
-iname 名前大文字小文字を区別せずファイルやディレクトリ名で検索
-mtime 日数更新日時で検索
-atime 日数最終アクセス日時で検索
-perm パーミッション値パーミッション値で検索
-size サイズファイルサイズで検索
-type 種類ファイルの種類で検索(f:ファイル、d:ディレクトリ、l:シンボリックリンク)
-user ユーザー名ユーザー名で検索
-uid ユーザーIDユーザーIDで検索
-group グループ名グループ名で検索

アクション

最後のアクションで、検索結果に対して何を行うのかを指定します。

主なアクション説明
-print検索結果を表示する(省略可能)
-ls属性情報も表示する
-exec コマンド{} \;検索結果に指定したコマンドを実行する。

アクションは、検索対象のファイルのパス名を表示する-printを使うのが一般的です。-printは省略が可能です。

実行例

名前で探す

名前を条件にして検索する場合は条件式の-nameを使います。-nameの後にスペースを入れてファイル名を指定します。アクションの-printは省略できます。

次の例では、カレントディレクトリを起点として、「.bashrc」という名前のファイルや「test」という名前のディレクトリを検索しています。

$ find . -name .bashrc
./.bashrc
$ find . -name test
./test
./test/test

上の例のようにファイル名やディレクトリ名がわかっていて完全に一致する場合は良いのですが、ファイルの数が増えてくるとそうもいきません。

一般的には、下の例のように引用符とメタキャラクタを組み合わせて使います。

$ find . -name "*.bash*"
./.bashrc
./.bash_history
./.bash_logout

引用符で指定しない場合はどうなるでしょうか。例えば、カレントディレクトリにabcとacbというディレクトリがあると仮定します。

$ ls
abc acb

引用符なしでaで始まる名前検索を実行すると以下のような結果になります。

$ find . -name a*
find: paths must precede expression: `acb'
find: possible unquoted pattern after predicate `-name'?

a*という引数を受け取ったfindが実際に実行するコマンドは以下のようなイメージです。

$ find . -name abc acb

abcをacbという引数で検索しろという意味のない文字列の命令になってしまい、エラーとなってしまいます。

引用符で囲むことで、a*がabcやacbに展開されずにコマンドが実行されます。

$ find . -name "a*"
./.local/share/applications
./.local/share/gnome-shell/application_state
./.local/share/evolution/addressbook
./.cache/evolution/addressbook
./acb
./abc

名前検索した結果の詳細情報を表示する

-nameにアクションコマンドの-lsを付加すれば、結果の属性を表示してくれます。

$ find . -name "*.bash*" -ls 13107203 4 -rw-r--r-- 1 ymizusawa ymizusawa 3771 12月 5 14:41 ./.bashrc 13107330 4 -rw------- 1 ymizusawa ymizusawa 901 1月 5 09:30 ./.bash_history 13107205 4 -rw-r--r-- 1 ymizusawa ymizusawa 220 12月 5 14:41 ./.bash_logout

日時で探す

日時を条件にして検索する場合は条件式の-*timeを使います。-*timeの後にスペースを入れて数値を指定します。

下の例では、ファイルやディレクトリを最終更新日時で検索しています。数値の0で1日以内を指定しています。

$ find . -mtime 0
.
(省略)
./acb
./.bash_history
./abc

下の例では、ファイルやディレクトリを最終アクセス日時で検索しています。数値の1で1日前を指定しています。

$ find . -atime 1
./.bashrc
./.profile
./.bash_logout

種類で探す

種類を条件にして検索する場合は条件式の-typeを使います。-typeの後に特定の文字を入れて種類を指定します。

次の例では-typeにdを指定して、カレントディレクトリ以下のディレクトリを検索しています。

$ find . -type d
.
./.config
./.config/pulse
./.config/update-notifier
(省略)
./テンプレート
./ミュージック
./ドキュメント
./acb
./ダウンロード
./abc

次の例では-typeにfを指定してカレントディレクトリ以下のファイルを検索しています。

$ find . -type f
./.config/pulse/
(省略)
./.sudo_as_admin_successful
./.bashrc
./.bash_history
./.profile
./.bash_logout

パーミッションを指定して検索

パーミッションを条件にして検索する場合は条件式の-permを使います。-permの後に数値を入れてパーミッションを指定します。

以下の例はカレントディレクトリ以下の読み取り権限のみ付与されたファイルを検索しています。

$ ls abc/abc.text -l
-r-------- 1 ymizusawa ymizusawa 0 1月 5 11:48 abc/abc.text
$ find . -perm 0400
./abc/abc.text
$ find . -perm 0400 -ls 13107300 0 -r-------- 1 ymizusawa ymizusawa 0 1月 5 11:48 ./abc/abc.text

パーミッションの数値の前に-を付与すると指定したパーミッションのいずれかの値が有効であればという条件で検索が可能です。

$ find . -perm -0400 -ls 13107202 4 drwxr-xr-x 17 ymizusawa ymizusawa 4096 1月 5 11:09 . 13107209 4 drwx------ 11 ymizusawa ymizusawa 4096 12月 5 16:27 ./.config 13107210 4 drwx------ 2 ymizusawa ymizusawa 4096 12月 5 15:38 ./.config/pulse
(省略) 13107316 4 drwxrwxr-x 2 ymizusawa ymizusawa 4096 1月 5 11:48 ./acb 13107322 0 -r-------T 1 ymizusawa ymizusawa 0 1月 5 11:48 ./acb/acb.text 13107251 4 drwxr-xr-x 2 ymizusawa ymizusawa 4096 12月 5 15:38 ./\343\203\200\343\202\246\343\203\263\343\203\255\343\203\274\343\203\211 13107330 4 -rw------- 1 ymizusawa ymizusawa 901 1月 5 09:30 ./.bash_history 13107204 4 -rw-r--r-- 1 ymizusawa ymizusawa 807 12月 5 14:41 ./.profile 13107205 4 -rw-r--r-- 1 ymizusawa ymizusawa 220 12月 5 14:41 ./.bash_logout 13107247 4 drwxrwxr-x 2 ymizusawa ymizusawa 4096 1月 5 11:48 ./abc 13107300 0 -r-------- 1 ymizusawa ymizusawa 0 1月 5 11:48 ./abc/abc.text

ちなみに、数値を4000にするとSUIDが有効のファイルを指定することになります。

エスパくん

スピードマスター問題集では、セキュリティの章でパーミションを/4000に指定するコマンドが正解の設問が出てきます。「find /bin -uid 0 -perm /4000」のように/を付与した場合、いずれかのビットが立っているファイルを検索します。ちなみに、-uid 0=ルートです。

複数の条件で検索

複数の条件で検索も可能です。下の例は種類と日時を指定しています。

$ find . -type f -mtime 0
(省略)
./acb/acb.text
./.bash_history
./abc/abc.text
$ find . -type d -mtime 0
.
./.config/dconf
./.local/share/tracker/data
./.local/share/gnome-shell
./.cache/tracker
./acb
./abc

検索結果にコマンドを実行

「-exec コマンド {} \;」で、検索結果に任意のコマンドを実行することができます。ちなみに、コマンドと{}の後ろにはスペースが必要ですのでお忘れなく。

下の例では、名前検索したファイルの属性を表示したのち、条件式を追加してパーミッションを変更しています。

$ find . -name "*abc.*" -ls 13107300 0 -r-------- 1 ymizusawa ymizusawa 0 1月 5 11:48 ./abc/abc.text
$ find . -name "*abc.*" -exec chmod 644 {} \;
$ find . -name "*abc.*" -ls 13107300 0 -rw-r--r-- 1 ymizusawa ymizusawa 0 1月 5 11:48 ./abc/abc.text

chmod 644の引数が{}に相当し、{}にはfindコマンドの検索結果が収納されています。ちなみに、\;の\はスケープ文字です。複雑に見えますが、こういう文法だと思って覚えてしまいましょう。

permission denied(許可がありません)の結果を除外する方法

一般ユーザーでfindコマンドを利用する時によく遭遇するのが「permission denied(許可がありません)」の表示。

$ find / -name "*.bash*"

のような条件式の場合、閲覧権限がないディレクトリやファイルを検索すると、permission denied(許可がありません)というエラー出力が大量に表示されてしまうことがままあります。

(省略)
/etc/skel/.bashrc
/etc/skel/.bash_logout
find: ‘/run/gdm3’: 許可がありません
find: ‘/run/udisks2’: 許可がありません
find: ‘/run/cups/certs’: 許可がありません
find: ‘/run/user/1000/inaccessible’: 許可がありません
find: ‘/run/user/125’: 許可がありません
find: ‘/run/sudo’: 許可がありません
find: ‘/run/speech-dispatcher’: 許可がありません
find: ‘/run/openvpn-server’: 許可がありません
find: ‘/run/openvpn-client’: 許可がありません
find: ‘/run/systemd/resolve/netif’: 許可がありません
find: ‘/run/systemd/unit-root’: 許可がありません
find: ‘/run/systemd/inaccessible’: 許可がありません
find: ‘/run/initramfs’: 許可がありません
find: ‘/root’: 許可がありません
find: ‘/boot/efi’: 許可がありません

こうしたエラー出力(=検索結果として不要な行)を削除する場合は、エラー出力を/dev/nullにリダイレクトしてしまいましょう。書式は以下の通り。

find [検索ディレクトリ] -name [名前] 2> /dev/null

先の例の後に「2> /dev/null」を追加して実行してみます。

$ find / -name "*.bash*" 2> /dev/null
/home/ymizusawa/.bash_logout
/home/ymizusawa/.bash_profile
/home/ymizusawa/.bash_history
/home/ymizusawa/.bashrc
/etc/bash_completion.d/yum-utils.bash
/etc/bash_completion.d/itweb-settings.bash
/etc/bash_completion.d/javaws.bash
/etc/bash_completion.d/policyeditor.bash
/etc/bash_completion.d/scl.bash
/etc/skel/.bash_logout
/etc/skel/.bash_profile
/etc/skel/.bashrc
/usr/share/doc/util-linux-2.23.2/getopt-parse.bash
/usr/share/doc/git-1.8.3.1/contrib/completion/git-completion.bash
/usr/share/bash-completion/completions/ibus.bash

エラー出力が表示されずに、検索結果がスッキリと表示されました。

関連リンク

余談

公式認定本のfindコマンド解説ページは以下の通りです。