Linuxでファイル内の特定の文字列を含む行を検索する方法の実務上の結論は「line番号指定はsed -nまたはawkのNR、pattern指定はgrep -nを使います。構造化dataではlineとrecordを混同せず専用parserを選びます。」です。検索語をliteral、extended regex、構造化recordのどれとして扱うかで手段を分けます。grepのmatchなし1とerror 2を維持し、秘密値を含む全文をlogへ出しません。
文字列検索はgrepを中心にする
file内で特定文字列を含む行を探す中心はgrepです。文字をそのまま探すなら-F、正規表現なら-E、行番号は-n、前後の文脈は-Cを使います。行番号だけを抜き出すsedやawkの例に置き換えると題意が変わるため、検索pattern、対象file、matchした行内容を一つの手順で確認します。
literal検索はgrep -nF — ‘ERROR[42]’ file、OR条件は-Eまたは複数-e、前後2行は-C 2です。patternがdashで始まる場合は-eまたは–でoptionと分離します。大文字小文字を無視する-i、単語境界-w、件数-cは意味を変えるため、必要性をsampleで確認し、広く付けた既定optionにしません。
literal・regex・record構造のどれを探すか決める
- 固定文字列か正規表現かを先に決める
- 対象file・encoding・binary有無を確認する
- matchなし1とerror2の扱いを定義する
- line単位で扱えない構造化dataを除外する
patternがuser入力ならoptionと誤認されない–、literalなら-Fを使います。multiline JSONやCSV recordのようにline境界が意味を持たない対象はgrep実行を止め、対応parserへ渡します。
grep -F・-E・-C・複数-eを比較する
固定文字列を行番号付きで検索
grep -nF -- 'ERROR[42]' ./app.log
-Fなら角括弧を正規表現として解釈せず、そのままの文字列を探します。match行にはline番号が付きます。
複数候補を拡張正規表現で検索
grep -nE -- 'ERROR|WARN' ./app.log
-Eは正規表現です。literal検索とはpatternの意味が違うため、fixtureで期待行を固定します。
match前後二行も表示
grep -nF -C 2 -- 'timeout' ./app.log
-C 2はcontextを追加します。match行とcontext行のseparatorを後続処理で区別します。
複数の固定patternを-eで指定
grep -nF -e 'disk full' -e 'read-only' -- ./system.log
patternがdashから始まる場合も-eでoptionと分離できます。
終了status 0・1・2を確認
grep -nF -- 'READY' ./service.log
status=$?
printf 'grep_status=%s\n' "$status"
0はmatchあり、1はmatchなし、2はerrorです。用途に応じた判定へ明示的にmappingします。
固定文字列・正規表現・前後行
通常grepはmatchありで0、matchなしで1、readや正規表現などのerrorで2を返します。1はtool故障ではありませんが、監視要件ではalert条件になり得ます。-nはline番号、-Cはseparatorを含むcontextを追加するため、後続parseでmatch行とcontext行を区別します。複数file時はfile名prefixの有無も固定します。
shell quotingでpatternが展開される、-Fと-Eを取り違える、empty patternで全行match、binary判定で表示が抑制される、localeとencodingでcharacter classが変わる場合があります。grepは基本的にline単位であり、newlineをまたぐ構造やquoted multiline recordを正しく検索する保証はありません。その場合はformat parserへ切り替えます。
matchなし1・read error2・binary抑制を分ける
- -Fと-Eを取り違えてpatternの意味を変える
- matchなし1とread error2を同じ空出力にする
- -Cのcontext行をmatch行として集計する
- binaryやencoding不一致を無理にtext表示する
- multiline recordを一行grepで完全に検索できると思う
status 1はmatchなし、2はreadまたはregex等のerrorです。binary抑制messageやpermission warningを0件へ丸めず、patternと対象hashを固定してerror解消後に同じfileを再検索します。
token、password、個人情報をpatternやmatch行のままprocess list、shell history、共有logへ残さないようにします。未知binaryをtext扱いでterminalへ出さず、fileで種類を確認します。grep結果をそのまま削除・置換commandへpipeせず、候補を固定してreviewします。原本を変えるoptionは検索手順へ含めません。
終了statusとencodingの検証
matchあり、なし、複数match、正規表現meta文字を含むliteral、先頭dash pattern、UTF-8、CRLF、binary、read不可をfixtureにします。-F/-E/-n/-C/-eのstdout、stderr、status 0/1/2を期待表へ照合します。対象fileのline数とhashを保存し、検索中更新されたrunは再現不能として再取得します。
複数fileを検索するとgrepはfile名をprefixへ付け、単一fileでは省略する場合があります。automationで列数を固定したいときは-H等の挙動をsampleで確認し、file名、line番号、内容を単純なcolon splitで壊さないようにします。file名や内容にcolonが含まれること、context行ではseparatorが異なることを想定し、必要ならNUL対応出力または専用の結果形式へ切り替えます。
binary dataを-aで強制的にtext扱いするとterminal制御byteを表示する可能性があります。まずfile –mimeで種類とencodingを確認し、必要な場合だけ隔離環境でbyte検索を設計します。UTF-8以外のtextはlocaleとpattern encodingを合わせ、文字化けした表示をmatchなしと誤認しません。圧縮fileは展開用readerを使い、原本を変更せずstreamとして渡します。
grepは改行で区切られたlineを基本単位にします。JSONのfield、CSVのquoted multiline、XML element、stack trace全体など構造を持つ対象は、一行に文字列があるかだけでは要件を表せません。patternを複雑にして擬似parserにせず、JSON/CSV/XMLやlog formatのparserでrecordを構築してからfield条件を評価します。
file名・line番号・statusを壊さず出力する
scriptではgrepの表示文言ではなくstatusとmachine-readableなfile/line情報を使います。matchなし1を正常か異常か用途ごとに定義し、error2を同じbucketへ入れません。file名にcolonやnewlineがあり得る場合はNUL対応optionや専用parserを検討します。巨大fileにはsize上限、timeout、最大match数を設定します。
line検索で足りないdataをparserへ渡す
固定文字列は-F、正規表現は-E、contextが必要なら-C、構造化JSONやmultiline recordはparserを選びます。repository横断検索ではignoreやbinary規則を確認した専用toolも有効ですが、articleの基本判定はgrepのpatternと終了statusです。検索結果から変更へ進む場合は別のreview手順へ切り離します。
合格はmatchあり・なし・read不可・binary fixtureでline番号とstatusが期待どおりになることです。構造化dataでrecord境界を壊す結果は採用せず、parser queryへ復旧します。

コメント