第4章 4-3 / システムを観察する

findとlocateで探す

このページで叩くコマンドと到達点

前提:4-2が完了し、~/practice(空ディレクトリ)が存在する状態から始めます。前ページまででサーバー全体の「体力」を把握できるようになりました。今度はその中から、目的の1つのファイルをピンポイントで探し出すfindコマンドを使いこなします。「あのファイル、どこに置いたっけ」を秒で解決できる力です。まず~/practiceの中に練習用の階層とファイルを作るところから始め、ページの最後にはすべて片付けてホームディレクトリだけの状態に戻します。

このページではSET 1〜3、合計30行のコマンドを上から順に叩きます。手打ち推奨(コピーは確認用)です。なお、より高速な検索コマンドlocateは、索引を作るためのplocateパッケージがまだサーバーに入っていないため、このページでは紹介にとどめます(第5章5-1でaptを学んだあと、自分でインストールできるようになります)。

SET 1 ― 練習用の階層を作り、find -name / -typeで探す

ubuntu@lightsail: ~
  1. $cd ~/practice
  2. $mkdir -p reports/2024 reports/2025 logs
  3. $touch reports/2024/sales.txt reports/2025/sales.txt
  4. $touch reports/2025/memo.md logs/app.log
  5. $ls -R
  6. $find .
  7. $find . -name "sales.txt"
  8. ./reports/2024/sales.txt
  9. ./reports/2025/sales.txt
  10. $find reports -name "sales.txt"
  11. $find . -type d
  12. $find . -type f
解説 ― SET 1 で何をしたか

1行目で練習用ディレクトリ~/practiceに移動し、2行目のmkdir -p reports/2024 reports/2025 logsで、深い階層を含む3つのディレクトリを一気に作成します(-pは親ディレクトリごとまとめて作る、第1章1-2で学んだオプションです)。34行目のtouchで、その中にいくつかの空ファイルを配置します。5行目のls -R(再帰的に一覧表示)で、今作った階層全体をひと目で確認しておきましょう。

6行目のfind .は、findコマンドの最も基本的な使い方です。.(今いる場所)を起点に、その配下にあるファイル・ディレクトリをすべて再帰的に(何階層下まででも)洗い出します。7行目のfind . -name "sales.txt"は、-nameオプションでファイル名を指定した検索です。出力例のように、2024年と2025年、2つのsales.txtが階層をまたいで両方見つかります。lsでは今いる場所しか見えませんが、findは配下の全階層を一気に検索できる点が最大の強みです。

8行目のfind reports -name "sales.txt"のように、検索の起点は.だけでなく任意のディレクトリを指定できます。reports配下だけに絞って検索したいときは、このように起点そのものを絞り込むほうが素早く済みます。9行目のfind . -type dは、-typeオプションで種類を指定した検索です。dはdirectory(ディレクトリ)の頭文字で、ファイルを除いてディレクトリだけを一覧します。10行目のfind . -type fは逆にf=file(ファイル)だけに絞り込みます。名前だけでなく「種類」で絞り込めることが確認できました。

POINT

find <探す場所> <条件>という語順を体に覚えさせましょう。lsは「今の場所」しか見ませんが、findは指定した場所から下の階層すべてを掘り下げて探してくれます。

ゆみちゃん
ゆみ

大学のレポート提出フォルダが「2024」「2025」みたいに年度ごとにネストしてて、目的のファイルがどこにあったか分からなくなること、あるあるだよね! そんなときこそfindの出番。lsで1つずつフォルダを開けて回らなくても、find . -name "ファイル名"一発で全階層から見つけ出してくれるよ!

SET 2 ― ワイルドカード・mtime・sizeで絞り込む

ubuntu@lightsail: ~/practice
  1. $find . -name "*.txt"
  2. $find . -name "*.log"
  3. $find . -iname "*.TXT"
  4. $find /etc -name "*.conf" 2>/dev/null | head
  5. $find /etc -maxdepth 1 -name "*.conf"
  6. $find . -mtime -1
  7. $find . -mtime +7
  8. $echo "sales data" > reports/2025/sales.txt
  9. $find . -size +0c
  10. ./reports/2025/sales.txt
  11. $find . -empty
解説 ― SET 2 で何をしたか

1行目のfind . -name "*.txt"は、ワイルドカード※1*を使い「拡張子が.txtのファイルすべて」を検索しています。*は「任意の文字列」を表す記号で、ここでは2つのsales.txtがまとめてヒットします。2行目のfind . -name "*.log"も同じ考え方で、今度はlogs/app.logが見つかります。-nameにはこのようにパターンを渡すことができ、正確なファイル名を思い出せなくても検索できるのが便利な点です。3行目のfind . -iname "*.TXT"は、-nameの代わりに-inameを使うことで、大文字・小文字を区別せずに検索するオプションです。.TXTと大文字で書いても.txtファイルがきちんと見つかります。

4行目のfind /etc -name "*.conf" 2>/dev/null | headは、システムの設定ファイル置き場/etcから.confファイルを探す実践的な例です。/etcには一般ユーザーが読めないディレクトリも含まれるため、権限エラーが大量に出力を埋め尽くしてしまいます。そこで使うのが2>/dev/nullという小技で、2>はエラー出力だけをリダイレクトする指定、/dev/nullは書き込んだものを何もかも消してしまう特殊な「捨て場所」です※2。エラーだけを黙らせて、欲しい結果だけを画面に残せます。5行目のfind /etc -maxdepth 1 -name "*.conf"は、-maxdepth 1で検索を1階層だけに制限し、/etc直下だけを素早く調べる書き方です。

6行目のfind . -mtime -1は、更新時刻(modified time)を条件にした検索です。-mtime -1は「1日以内に更新されたもの」、7行目のfind . -mtime +7は「7日より前に更新されたもの」を意味します。-(未満)と+(より前・より大きい)の向きに注意してください。今作ったばかりのファイルはすべて1日以内の更新なので、6行目には全ファイルが、7行目には何もヒットしないはずです。

8行目でreports/2025/sales.txtに文字列を書き込んでサイズを持たせたうえで、9行目のfind . -size +0cを実行すると、出力例のようにサイズが0バイトより大きいファイルだけが見つかります(cはバイト単位を表す指定です)。最後の10行目find . -emptyは逆に、中身が空のファイル・ディレクトリだけを探す専用オプションです。

POINT

2>/dev/nullは「エラーメッセージだけを闇に葬る」おまじないとして、findを実務で使うときにセットで覚えておくと画面が一気に見やすくなります。

SET 3 ― -exec・xargsでヒットしたファイルを操作する

ubuntu@lightsail: ~/practice
  1. $find . -name "*.txt" -exec ls -l {} \;
  2. -rw-rw-r-- 1 ubuntu ubuntu 0 7月 3 10:02 ./reports/2024/sales.txt
  3. -rw-rw-r-- 1 ubuntu ubuntu 11 7月 3 10:05 ./reports/2025/sales.txt
  4. $find . -name "*.md" -exec cat {} \;
  5. $find . -name "*.md" -exec mv {} logs/ \;
  6. $ls logs
  7. $find . -type f | xargs ls -l
  8. $find . -name "*.log" | xargs wc -l
  9. $find . -type f -name "*.txt" -exec rm {} \;
  10. $find . -name "*.txt"
  11. $cd ~
  12. $rm -r ~/practice/reports ~/practice/logs
解説 ― SET 3 で何をしたか

1行目のfind . -name "*.txt" -exec ls -l {} \;は、findで見つけたファイルに対して、その場で別のコマンドを実行する書き方です。-execのあとに実行したいコマンドを書き、見つかったファイルが入る場所に{}(波括弧)を置き、コマンドの終わりを\;(バックスラッシュ+セミコロン)で締めます。出力例のように、2つの.txtファイルそれぞれに対してls -lが実行され、詳細情報が表示されます。2行目のfind . -name "*.md" -exec cat {} \;も同じ形で、見つかった.mdファイルの中身をcatで表示しています。

3行目のfind . -name "*.md" -exec mv {} logs/ \;のように、-execにはmvcpのような複数の引数を取るコマンドも組み合わせられます。ここでは見つかった.mdファイルをlogsディレクトリへ移動しています。4行目のls logsで、memo.mdが移動できていることを確認します。

5行目のfind . -type f | xargs ls -lは、-execとよく似た目的をパイプとxargsで実現する書き方です。xargs※3は、パイプで受け取った出力(この場合はfindが見つけたファイル名の一覧)を、後ろに書いたコマンドの引数として1つずつ渡してくれる橋渡し役です。-exec ... {} \;は見つかるたびに1回ずつコマンドを起動するのに対し、xargsは複数のファイル名をまとめて1回のコマンド実行に渡せるため、対象が多いときはこちらの方が高速に動作します。6行目のfind . -name "*.log" | xargs wc -lでは、見つかったログファイルの行数をwc -lでまとめて数えています。

7行目のfind . -type f -name "*.txt" -exec rm {} \;は、これまで確認と表示だけに使っていた-execを、いよいよ削除(rm)に使う例です。-type f-nameを組み合わせて条件を絞り込んでから実行することで、意図しないディレクトリごと削除してしまう事故を防いでいます。8行目のfind . -name "*.txt"で再検索し、何もヒットしなくなった(削除できた)ことを確認します。

最後に9行目のcd ~でホームディレクトリへ戻り、10行目のrm -r ~/practice/reports ~/practice/logsで、このページで作った練習用の階層をすべて削除します。これで~/practiceは再び空のディレクトリに戻り、次のページへ引き継ぐ状態が整いました。

ゆみちゃん
ゆみ

-exec ... {} \;、最初は呪文にしか見えないと思う! でも「見つかったファイルがここに入りますよ」の印が{}、「コマンドの終わりですよ」の印が\;って覚えれば大丈夫。ちなみにfindと同じ目的でもっと爆速に検索できるlocateってコマンドもあるんだけど、それは第5章でaptの使い方を覚えたあとに自分でインストールできるようになるから、楽しみにしててね!

POINT

-exec ... rm {} \;のような削除系コマンドを使う前には、必ず同じ条件で-exec ls -l {} \;や単なる検索を先に実行し、「意図した通りのファイルだけがヒットしているか」を目で確認してから削除に切り替える癖をつけましょう。

まとめ

4-3では、階層の深いディレクトリの中から目的のファイルを探し出すfindコマンドを一通り体験しました。このページで叩けるようになったコマンドを一覧にまとめます。

コマンド何をするか覚え方
find .今いる場所から配下すべてを再帰的に洗い出すfind=探す、.=ここから下
find . -name "<名前>"ファイル名で検索する-name=名前で指名
find . -name "*.txt"ワイルドカードで拡張子検索する*=何でもいい部分
find . -type d / -type fディレクトリ/ファイルだけに絞り込むd=directory、f=file
2>/dev/nullエラー出力だけを捨てて画面を見やすくするエラーだけ闇送りにする
find . -mtime -1 / +7更新日時で絞り込む-1=1日以内、+7=7日より前
find . -size +0cファイルサイズで絞り込むc=バイト単位
find . -exec <cmd> {} \;見つけたファイルに対してコマンドを実行する{}=見つかった物が入る場所
find . | xargs <cmd>見つかったファイル名をまとめて次のコマンドに渡すxargs=引数の橋渡し役

次のページ「4-4. アーカイブとバックアップ」では、探し出したファイルを1つにまとめて圧縮し、バックアップとして保存するtarコマンドを学びます。

脚注 ─ 用語解説
  1. ワイルドカード*のように「任意の文字列」を表す特殊記号。ファイル名の一部だけがわかっているときの検索に使う。
  2. /dev/null … 書き込んだデータをすべて消し去る特殊なファイル。不要な出力(主にエラー)の捨て場所として使われる。
  3. xargs … パイプで受け取った文字列の並びを、別のコマンドの引数として渡す橋渡しコマンド。大量のファイルをまとめて処理したいときに使う。