Linuxでテキストファイルの特定のパターンを検索する方法を安全に進める結論は「文字列そのものはgrep -F、正規表現はgrep -Eを明示し、-nで行番号、-rでは–includeと–exclude-dirで範囲を固定します。0件とerrorは終了codeで分けます。」です。GNU grep 3.12を中心に、text encoding、locale、再帰範囲、binary判定が結果へ影響するという前提を外すと同じ入力でも結果が変わります。まず読み取り確認で現状を固定し、その後に必要最小限の操作、検証、復元を分けて行います。 確認ポイント:grepは一致0、非一致1、処理errorは1より大きい値として分けて扱います。
grep検索のroot・pattern・encodingを固定する
最初のcommandは状態を変えないものに限定します。対象件数、pathまたはresource名、実体のversion、必要権限をそろえ、想定外が一つでもあれば操作段階へ進みません。
- 検索対象のrootとfile拡張子を列挙する
- 固定文字列か正規表現かを決める
- encodingとbinary fileの混在を確認する
- 一致なしを正常とするか決める
想定と違う結果は障害ではなく停止条件です。条件を一つずつ直し、再取得した一覧をreviewします。
一致行と終了statusを一緒に読む
grepは一致したlineを出力します。-Fはmetacharacterを文字として扱い、-Eは正規表現として解釈します。終了code 0は一致、1は一致なし、2はerrorです。localeはcharacter classや範囲表現へ影響し、newlineをまたぐ一般的な検索には向きません。
空出力は一致なし、対象なし、権限不足、parse失敗のいずれでも起こります。error streamと条件別の件数を分けます。
固定文字列から再帰検索へ広げる
固定文字列を行番号付きで検索
grep -nF -- 'ERROR 42' ./app.log
patternをoptionと誤認させないため–の後へ置きます。
複数候補を拡張正規表現で検索
grep -nE -- 'WARN|ERROR' ./app.log
-Eを明示し、引用符でshell展開を防ぎます。
対象拡張子だけを再帰検索
grep -rnF --include='*.conf' --exclude-dir='.git' -- 'timeout=' ./project
検索rootと除外directoryをreviewしてから実行します。
前後の文脈も表示
grep -nF -C 2 -- 'connection refused' ./service.log
出力行が重なる場合はgroup化されるため件数とは分けて読みます。
終了codeを記録
if grep -nF -- 'ready' ./status.log; then
printf '%s\n' 'matched'
else
rc=$?
case $rc in
1) printf '%s\n' 'no match' ;;
*) printf 'grep_error_rc=%s\n' "$rc" >&2; exit "$rc" ;;
esac
fi
grepは一致なし1、error 2なので、表示が空という理由だけで同一扱いしません。
grepで誤判定を招く五つの指定
- 固定文字列を正規表現として解釈する
- 空patternが全lineへ一致する
- grep -rと-Rのsymbolic link動作を混同する
- 一致なしとread errorを同じ空結果にする
- file名にnewlineやleading dashがある前提を外す
再試行前に入力、path、版、権限を見直し、同じ失敗を繰り返さない記録を残します。
検索結果へ機密logを残さない
検索は読み取りですが、機密logをterminal履歴、共有folder、CI artifactへ残す可能性があります。recursive検索のrootを/全体へ広げず、permission errorとbinary warningを別記録にします。結果を加工するときも原本へredirectしません。
backupを作るだけで終えず、読めることと正しい世代であることを確認します。復旧後も同じhealth checkを行います。
fixtureとgrep versionを記録する
一致あり、なし、read不可、UTF-8、binary byte、leading dashを含むfile名のsampleを作ります。期待line番号と終了codeを照合し、recursive時は対象file一覧も保存します。
担当者が変わっても再現できるよう、版、入力sample、実行時刻、結果hashを残します。
binary・権限error・0件を別記録にする
対象範囲を確定する段階では「encodingとbinary fileの混在を確認する」が判断材料になります。また「一致なしを正常とするか決める」を満たさない場合は、技術的に実行できても運用上の準備不足です。
実例のうち「固定文字列を行番号付きで検索」はbaselineを得る用途、「複数候補を拡張正規表現で検索」は対象をさらに具体化する用途として使い分けます。両方の出力を同じ形式へ無理に整形せず、元の型と件数を保持したまま比較します。期待値は画面の見た目ではなく、対象ID、path、時刻など再照合できる列で定義します。
再帰検索を本番データへ向ける前に、検索対象・対象外・大文字小文字違いを含む小さな検証用ディレクトリで件数を確かめます。結果を保存する場合は、検索ルート、拡張子、パターン、実行時刻も記録してください。更新が続くログ置き場では検索中にも件数が変わるため、重要な照合は同じスナップショットまたは変更が止まった時間帯で再実行します。
grep の終了値は、0が一致あり、1が一致なし、2以上が読み取りや構文などのエラーを示します。検索直後に rc=$? で保存し、一致なしを障害と混同しないようにします。パイプへ渡した場合は既定では末尾コマンドの終了値になるため、検索そのものの成否が必要なBash手順では PIPESTATUS または限定した pipefail で確認します。
再試行の前に、固定文字列を正規表現として解釈していないか、空patternが全行へ一致していないかを確認します。grep -r と -R はsymbolic linkの追跡範囲が異なるため、まず小さな検証ツリーで -nF の結果を確定し、必要な場合だけ正規表現やlink追跡を追加します。
検索結果を共有する前に、認証token、個人情報、秘密鍵などが一致行へ含まれていないか確認します。結果ファイルは新規の制限された保存先へ出し、元ファイルのmodeや所有者は変更しません。filenameに空白や改行があり得る自動処理では、行区切りの一覧を次の破壊的処理へ渡さないでください。
再現に必要なのは、grepのversionとlocale、検索root、pattern、-F/-E、再帰・linkのoption、終了値、一致件数、読み取りエラーです。0件だった場合も終了値1とエラー2以上を分け、権限不足で読めなかったdirectoryを明記します。読み取り検索だけならbackupやrollbackは発生しません。
完了条件は、既知の一致fixtureが検出され、非一致fixtureが除外され、終了値と件数を説明できることです。さらに対象外directoryとsymbolic linkの扱い、読めなかったpathを確認します。更新中のログでは同じ結果を期待せず、検索時刻と対象snapshotを記録して判断します。
Linux text file内のpattern検索の開始記録には「検索対象のrootとfile拡張子を列挙する」を最初に置きます。続けて「固定文字列か正規表現かを決める」を確認すると、対象違いと環境違いを作業前に分けられます。
grepの判定を自動化するときは、終了値0を一致あり、1を一致なし、2以上を読取りや構文のerrorとして分けます。文字列をそのまま探すなら-F、拡張正規表現なら-Eを選び、正規表現の記号を固定文字列へ混ぜません。ファイル名に改行が入り得る一括処理ではfindの-print0とgrepの対応オプションを使い、画面表示用の改行区切りを処理契約にしないことが重要です。

コメント