LPIC Level1 復習ラジオ 11:検索コマンド
音声
目次
検索コマンドの使い分け
Linuxの検索は、「ファイルの中身を探す」「ファイル名や属性から探す」「コマンドの場所を探す」に分けると整理しやすくなります。
| コマンド | 主な検索対象 | 特徴 |
|---|---|---|
grep |
ファイル内容やコマンド出力 | 指定したパターンに一致する行を抽出する |
find |
実際のディレクトリツリー | 名前、種類、サイズ、時刻、所有者、権限などをその場で調べる |
locate |
ファイル名データベース | 高速だが、データベース更新後の状態を基に検索する |
which |
PATHから実行される外部コマンド |
コマンド名に対応する実行ファイルのパスを調べる |
whereis |
実行ファイル、ソース、manページ | 標準的な配置場所などから、コマンドに関係するファイルを探す |
grepの基本
grepは、入力から指定したパターンに一致する行を探し、標準では一致した行を表示します。
grep 'error' app.log
grep 'root' /etc/passwd
command | grep 'pattern'
基本形は、次のとおりです。
grep [オプション] パターン [ファイル...]
パターンにシェルで特別な意味を持つ文字や空白が含まれる場合に備え、通常は引用符で囲みます。
複数ファイルから検索する
grep 'ERROR' app.log system.log
grep 'nameserver' /etc/*.conf
複数ファイルを検索した場合、通常は一致行の前にファイル名が表示されます。
標準入力から検索する
ps aux | grep 'sshd'
journalctl | grep 'failed'
ファイル名を指定しなければ、grepは標準入力を検索します。パイプを使うと、別コマンドの出力から必要な行だけを抽出できます。
固定文字列として検索する
grep -F '192.168.1.10' access.log
grep -F '[ERROR]' app.log
-Fは、パターンを正規表現ではなく固定文字列として扱います。ドット、角括弧、アスタリスクなどを、その文字自体として探したい場合に便利です。
終了ステータス
| 終了ステータス | 意味 |
|---|---|
0 | 一つ以上の一致が見つかった |
1 | 一致が見つからなかった |
2 | ファイルを読めないなどのエラーが発生した |
grep -q 'sshd' /etc/services
echo $?
-qは検索結果を表示せず、終了ステータスだけを利用したい場合に使います。シェルスクリプトの条件判定でよく利用されます。
grepの主なオプション
一致方法を変える
grep -i 'error' app.log
grep -v '^#' config.conf
grep -w 'root' /etc/passwd
grep -x 'enabled' status.txt
| オプション | 意味 |
|---|---|
-i | 大文字と小文字を区別しない |
-v | パターンに一致しない行を表示する |
-w | 単語全体が一致する行だけを対象にする |
-x | 行全体がパターンに一致する行だけを対象にする |
-F | パターンを固定文字列として扱う |
-E | 拡張正規表現として扱う |
表示内容を変える
grep -n 'ERROR' app.log
grep -H 'root' /etc/passwd
grep -h 'root' file1 file2
grep -o 'error' app.log
grep --color=auto 'error' app.log
-n:行番号を表示する-H:ファイル名を必ず表示する-h:複数ファイルでもファイル名を表示しない-o:一致した部分だけを一行ずつ表示する--color=auto:端末への出力時に一致部分を色付けする
件数やファイル名だけを表示する
grep -c 'ERROR' app.log
grep -l 'ERROR' *.log
grep -L 'ERROR' *.log
-c:一致した行数をファイルごとに表示する-l:一致を含むファイル名だけを表示する-L:一致を含まないファイル名だけを表示する
grep -cが数えるのは、一致回数ではなく一致した行数です。一行に同じ単語が複数回あっても、その行は一行として数えられます。
前後の行も表示する
grep -A 3 'ERROR' app.log
grep -B 2 'ERROR' app.log
grep -C 2 'ERROR' app.log
-A 数値:一致行の後を指定行数表示する-B 数値:一致行の前を指定行数表示する-C 数値:一致行の前後を指定行数表示する
ディレクトリを再帰検索する
grep -r 'PermitRootLogin' /etc/ssh
grep -R 'server_name' /etc/nginx
-rはディレクトリ以下を再帰検索します。GNU grepでは、-Rはコマンドライン上や検索途中で見つけたシンボリックリンクもたどる動作になります。意図しない範囲へ広がらないよう、検索起点を具体的にします。
grepと正規表現
grepのパターンには正規表現を使えます。ここでは検索に必要な基本だけを確認します。正規表現の詳しい整理は、第19回で扱います。
| 記号 | 基本的な意味 | 例 |
|---|---|---|
^ | 行の先頭 | grep '^root:' /etc/passwd |
$ | 行の末尾 | grep '/bin/bash$' /etc/passwd |
. | 任意の一文字 | grep 'h.st' file |
* | 直前の要素の0回以上の繰り返し | grep 'ab*c' file |
[abc] | 角括弧内のいずれか一文字 | grep '[Ee]rror' file |
[^abc] | 角括弧内以外の一文字 | grep '[^0-9]' file |
基本正規表現と拡張正規表現
grep 'error\|warning' app.log
grep -E 'error|warning' app.log
grep -E '^(error|warning):' app.log
標準のgrepは基本正規表現を使います。-Eでは拡張正規表現となり、|や()などをバックスラッシュなしで扱えます。
シェルのワイルドカードとの違い
シェルの*.logはファイル名を展開するワイルドカードです。正規表現の.*は、任意の文字が0回以上続く部分を表します。
# シェルが *.log をファイル名へ展開する
grep 'ERROR' *.log
# grepが正規表現として ERROR.*failed を解釈する
grep 'ERROR.*failed' app.log
この二つを混同しないことが重要です。
findの基本
findは、指定した検索起点から実際のディレクトリツリーをたどり、各項目に対して条件を評価します。
find 検索起点 条件 処理
例えば、現在のディレクトリ以下から.logで終わる通常ファイルを探す場合は、次のように指定します。
find . -type f -name '*.log'
.:検索を始める場所-type f:通常ファイルだけを対象にする条件-name '*.log':ファイル名の条件- 処理を省略した場合:標準では
-printでパスを表示する
パターンは引用符で囲む
find . -name '*.log'
*.logを引用符で囲まないと、findが受け取る前にシェルが現在のディレクトリのファイル名へ展開する可能性があります。findへパターンをそのまま渡すため、引用符で囲みます。
検索する深さを制限する
find . -maxdepth 1 -type f
find . -mindepth 2 -maxdepth 3 -type d
-maxdepth 数値:検索起点から指定した深さまで調べる-mindepth 数値:指定した深さより浅い項目には条件や処理を適用しない
-maxdepth 1では、検索起点自身と、その直下までを対象にします。
複数の検索起点
find /etc /usr/local/etc -name '*.conf'
findでは、複数の検索起点を指定できます。権限のない場所へ入ると、Permission deniedなどが標準エラー出力へ表示される場合があります。
findの検索条件
名前で探す
find . -name '*.txt'
find . -iname '*.jpg'
find . -path '*/cache/*'
-name:パスの最後の名前、ベースネームを大文字小文字を区別して照合する-iname:大文字小文字を区別せず名前を照合する-path:検索起点からのパス全体をパターンと照合する
種類で探す
find . -type f
find . -type d
find . -type l
| 指定 | 対象 |
|---|---|
-type f | 通常ファイル |
-type d | ディレクトリ |
-type l | シンボリックリンク |
-type b | ブロックデバイス |
-type c | キャラクターデバイス |
-type p | 名前付きパイプ |
-type s | ソケット |
サイズで探す
find . -type f -size +100M
find . -type f -size -10k
find . -type f -empty
+数値:指定値より大きい-数値:指定値より小さいc:バイトk:1024バイト単位M:メビバイト単位G:ギビバイト単位-empty:空の通常ファイル、または項目のないディレクトリ
時刻で探す
find . -type f -mtime -1
find . -type f -mtime +30
find . -type f -mmin -60
find . -type f -newer reference.txt
-mtime:内容の更新時刻を24時間単位で調べる-mmin:内容の更新時刻を分単位で調べる-newer ファイル:指定した参照ファイルより新しく更新された項目を探す
-mtime -1は、24時間単位で見て1未満、つまり概ね過去24時間以内に更新された項目を探します。-mtime +30は、丸30日を超えて古い項目が対象になります。
所有者や権限で探す
find /home -user alice
find /srv -group developers
find . -type f -perm 0644
find . -type f -perm -002
find . -type f -perm /111
-user:所有ユーザー-group:所有グループ-perm 0644:モードが完全に一致する-perm -002:指定したビットがすべて設定されている-perm /111:指定した実行ビットのどれか一つ以上が設定されている
条件を組み合わせる
find . -type f -name '*.log' -size +10M
find . \( -name '*.jpg' -o -name '*.png' \) -type f
find . -type f ! -name '*.bak'
- 条件を並べる:論理AND。両方を満たす
-o:論理OR。どちらかを満たす!または-not:条件を反転する\(と\):条件をグループ化する
丸括弧はシェルでも特別な意味を持つため、バックスラッシュでエスケープするか引用符を使います。
findで見つけた項目を処理する
詳しい情報を表示する
find . -type f -name '*.log' -print
find . -type f -name '*.log' -ls
-printはパスを表示します。-lsは、inode番号、ブロック数、権限、所有者、サイズ、時刻、パスなどを表示します。
-execでコマンドを実行する
find . -type f -name '*.log' -exec grep -H 'ERROR' {} \;
find . -type f -name '*.log' -exec grep -H 'ERROR' {} +
{}:見つかったパスへ置き換えられる\;:一項目ごとにコマンドを実行する+:複数のパスをまとめて、一回以上のコマンド呼び出しに渡す
多数のファイルを処理する場合は、可能なら{} +の方が、項目ごとにプロセスを起動する{} \;より効率的です。
ファイル名を安全に受け渡す
find . -type f -name '*.log' -print0 | xargs -0 grep -H 'ERROR'
ファイル名には空白、改行、引用符なども使用できます。-print0はNUL文字で区切って出力し、xargs -0はNUL区切りで受け取ります。
ただし、単純な処理ならfind -exec ... {} +を使う方が、空白を含む名前も安全に扱いやすく、コマンドも読みやすい場合があります。
削除する
find ./cache -type f -name '*.tmp' -print
find ./cache -type f -name '*.tmp' -delete
-deleteは、見つかった項目を実際に削除します。まず同じ条件で-printし、対象が正しいことを確認してから実行します。
locateとupdatedb
locateは、あらかじめ作成されたファイル名データベースを検索します。実際のディレクトリを毎回たどるfindより高速に結果を返せます。
locate sshd_config
locate '*.service'
locate -i readme
locate -c '.conf'
-i:大文字と小文字を区別しない-c:パスを表示せず一致数だけを表示する-b:フルパスではなく、最後のファイル名部分だけを照合する-e:現在も存在する項目だけを表示する-r:パターンを正規表現として扱う
データベース検索であることに注意する
locateのデータベースには、最後に更新された時点で存在したファイル名が記録されています。
- 作成したばかりのファイルが見つからない場合がある
- 削除済みのファイルが結果へ残っている場合がある
- 除外設定されたディレクトリやファイルシステムは登録されない場合がある
updatedb
sudo updatedb
updatedbは、locateが使用するファイル名データベースを更新します。通常は定期処理で実行されますが、環境によって更新頻度や対象範囲が異なります。
ディストリビューションによってはGNU locateではなく、plocateやmlocate系の実装が使われます。また、最小構成ではlocate自体が未導入の場合があります。
locate --version
man locate
man updatedb
利用できるオプションやデータベースの場所は実装によって異なるため、対象環境のバージョンとmanページを確認します。
findとの使い分け
| 項目 | find | locate |
|---|---|---|
| 検索対象 | 現在の実ディレクトリツリー | 更新済みデータベース |
| 速度 | 範囲が広いと時間がかかる | 一般に高速 |
| 検索条件 | 名前、種類、サイズ、時刻、権限など | 主にパス名 |
| 最新性 | 実行時点の状態 | データベース更新時点の状態 |
which
whichは、シェルが外部コマンドを探すときに使うPATHを基に、コマンド名に対応する実行ファイルのパスを表示します。
which ls
which python3
which -a python3
-aを利用できる実装では、PATH上で見つかる候補をすべて表示します。
PATH
echo "$PATH"
PATHには、コマンドを探すディレクトリがコロン区切りで登録されています。シェルは通常、左から順に検索し、最初に見つかった実行可能なコマンドを使用します。
whichだけでは分からない場合
コマンド名は、外部実行ファイルだけでなく、シェルの組み込みコマンド、関数、エイリアスの場合があります。whichの実装によっては、これらを正確に反映しません。
type ls
type -a ls
command -v ls
alias ls
type:コマンド名がエイリアス、関数、組み込み、外部ファイルのどれとして解釈されるか確認するtype -a:同じ名前で利用可能な候補をすべて表示するcommand -v:シェルがコマンド名をどのように解決するかを表示する
「実際にこのシェルで何が実行されるか」を確認したい場合は、whichだけでなくtypeやcommand -vも使います。
ハッシュされたコマンド
Bashは一度見つけた外部コマンドのパスを記憶することがあります。PATHや実行ファイルを変更した後に結果が不自然な場合は、次のように確認・消去できます。
hash
hash -r
whereisと実践的な確認手順
whereis
whereisは、指定したコマンド名について、実行ファイル、ソースファイル、manページを標準的なLinuxの配置場所や設定された検索パスから探します。
whereis ls
whereis ssh
whereis -b bash
whereis -m bash
whereis -s bash
whereis -l
| オプション | 検索対象 |
|---|---|
-b | 実行ファイル |
-m | manページやドキュメント |
-s | ソースファイル |
-l | whereisが使用する検索パスを表示する |
whereisは、ファイルシステム全体を任意の名前で検索するコマンドではありません。コマンドに関係するファイルを、既知の配置場所から探す用途です。
whichとの違い
| 項目 | which | whereis |
|---|---|---|
| 主な目的 | PATH上の実行ファイルを確認する | 実行ファイル、manページ、ソースを探す |
| 検索範囲 | 主にPATH | 標準配置、PATH、MANPATHなど |
| エイリアス・関数 | 実装により正確に扱えない | 対象外 |
| manページ | 探さない | 探せる |
目的別の確認例
# 設定ファイル内の文字列を探す
grep -Rni 'PermitRootLogin' /etc/ssh
# 実際に存在する設定ファイルを名前から探す
find /etc -type f -name '*ssh*'
# システム全体のファイル名を高速に探す
locate sshd_config
# PATH上のpython3を確認する
which python3
# シェルで実際に解決されるpython3を確認する
type -a python3
command -v python3
# bashの実行ファイルとmanページを探す
whereis bash
Permission deniedを整理する
find / -name 'target' 2>/tmp/find-errors.log
grep 'Permission denied' /tmp/find-errors.log
検索結果でなく、アクセスできないディレクトリのエラーが大量に出る場合があります。標準エラー出力を別ファイルへ分けると、結果とエラーを区別できます。
2>/dev/nullでエラーを捨てる方法もありますが、重要な入出力エラーまで見えなくなります。原因調査では、まず別ファイルへ保存して確認する方が安全です。
基本の選び方
- ファイル内容を検索するなら
grep - 現在の実ファイルを属性付きで探すなら
find - 名前だけを高速に探すなら
locate - PATH上の外部コマンドなら
which - シェルで実際に解決されるものなら
typeまたはcommand -v - 実行ファイルとmanページなどをまとめて探すなら
whereis
詳しい使い方は、次のマニュアルでも確認できます。
man grep
man find
man locate
man updatedb
man which
man whereis
help type
help command
30秒チェック
- ファイル内容からパターンに一致する行を抽出するコマンドは何でしょうか。
grep -cは、一致した文字列の回数と一致した行数のどちらを表示するでしょうか。find . -name '*.log'で、パターンを引用符で囲む理由は何でしょうか。findの-exec ... {} \;と-exec ... {} +の主な違いは何でしょうか。locateで作成直後のファイルが見つからないことがあるのはなぜでしょうか。whichとwhereisの主な違いは何でしょうか。
答えを表示
grep- 一致した行数
- シェルによるワイルドカード展開を防ぎ、パターンをそのままfindへ渡すため
\;は項目ごとに実行し、+は複数項目をまとめて実行する- 実際のファイルシステムではなく、最後に更新されたファイル名データベースを検索するため
whichは主にPATH上の実行ファイルを探し、whereisは実行ファイル、manページ、ソースなどを標準配置から探す
要約
grepは、入力からパターンに一致する行を検索します。grep -iは大文字小文字を無視し、-vは不一致行、-nは行番号を表示します。grep -cは一致行数、-lは一致を含むファイル名を表示します。findは、検索起点から実際のディレクトリツリーをたどり、名前、種類、サイズ、時刻、権限などを調べます。findの名前パターンは、シェル展開を防ぐため引用符で囲みます。-exec ... {} +は、見つかった複数のパスをまとめてコマンドへ渡します。locateは高速ですが、最後に更新されたファイル名データベースを検索します。updatedbは、locate用のデータベースを更新します。whichは主にPATH上の外部コマンドを調べ、実際のシェル解決はtypeやcommand -vでも確認します。whereisは、コマンドの実行ファイル、manページ、ソースなどを標準的な場所から探します。