ファイルを作成・コピーする
実例を試すためのディレクトリとテキストを作ります。printfの出力を>でファイルへ保存し、>>で追記します。
mkdir -p data/archive
printf 'INFO start\nERROR disk full\nINFO finish\n' > data/app.log
cp data/app.log data/archive/app.log
cat data/app.logINFO start
ERROR disk full
INFO finish上書きの>は既存ファイルの内容を消す可能性があります。追記したいときは>>を使い、処理前に対象を確認します。
findでファイルを探す
findは開始場所と条件を指定してファイルを検索します。まず表示だけを行い、条件が正しいと確認してからコピーや削除へ進みます。
find data -type f -name '*.log' -print | sortdata/archive/app.log
data/app.log'*.log'を引用するのは、シェルが先にワイルドカードを展開しないようにするためです。-type fは通常ファイル、-type dはディレクトリを意味します。
grepで必要な行を抽出する
grepは文字列に一致する行を表示します。-nで行番号、-iで大文字・小文字を区別しない検索、-vで一致しない行を表示できます。
grep -n 'ERROR' data/app.log
grep -v 'INFO' data/app.log2:ERROR disk full
ERROR disk full一致する行がない場合、grepは終了ステータス1を返します。これは検索結果が空という意味で、必ずしもスクリプト全体の異常ではありません。用途に応じて扱いを決めます。
ファイルを一行ずつ読む
行単位のデータを安全に処理する基本形は、while IFS= read -r lineです。入力リダイレクトを使うと、標準入力からファイルを読み込めます。
line_number=0
while IFS= read -r line; do
((line_number++))
printf '%02d: %s\n' "$line_number" "$line"
done < data/app.log01: INFO start
02: ERROR disk full
03: INFO finishIFS=は行頭・行末の空白を保ち、read -rはバックスラッシュをそのまま扱います。データを壊さず読むための定型として覚えましょう。
パイプで集計する
複数のコマンドをパイプでつなぐと、検索、抽出、並べ替え、集計を段階的に書けます。
cut -d' ' -f1 data/app.log | sort | uniq -c 1 ERROR
2 INFOcut -d' ' -f1は空白区切りの1列目を取り出します。sortで同じ値を隣り合わせにしてからuniq -cで数えます。入力に連続空白がある場合は、awkなど別の方法が適することもあります。
awk '$1 == "ERROR" { print NR, $0 }' data/app.log2 ERROR disk fullNRは行番号、$0は行全体です。テキスト処理は入力形式に強く依存するため、実際のデータを数行確認してから使います。
練習:エラーログを保存する
data/app.logからERRORを含む行だけをdata/errors.logへ保存し、保存した件数を表示してください。
grep 'ERROR' data/app.log > data/errors.log || true
count=$(wc -l < data/errors.log)
printf 'エラー: %s件\n' "$count"
cat data/errors.logエラー: 1件
ERROR disk full次は関数と引数へ進み、処理を再利用できる形へ整理します。