シェルスクリプト

ファイルとテキスト処理

練習用ファイルを作り、検索・抽出・集計を組み合わせて処理します。

シェルスクリプト入門の講座一覧

01

ファイルを作成・コピーする

実例を試すためのディレクトリとテキストを作ります。printfの出力を>でファイルへ保存し、>>で追記します。

練習データを作るCOMMAND
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.log
実行結果OUTPUT
INFO start
ERROR disk full
INFO finish

上書きの>は既存ファイルの内容を消す可能性があります。追記したいときは>>を使い、処理前に対象を確認します。

02

findでファイルを探す

findは開始場所と条件を指定してファイルを検索します。まず表示だけを行い、条件が正しいと確認してからコピーや削除へ進みます。

拡張子で検索COMMAND
find data -type f -name '*.log' -print | sort
実行結果OUTPUT
data/archive/app.log
data/app.log

'*.log'を引用するのは、シェルが先にワイルドカードを展開しないようにするためです。-type fは通常ファイル、-type dはディレクトリを意味します。

03

grepで必要な行を抽出する

grepは文字列に一致する行を表示します。-nで行番号、-iで大文字・小文字を区別しない検索、-vで一致しない行を表示できます。

エラー行を探すCOMMAND
grep -n 'ERROR' data/app.log
grep -v 'INFO' data/app.log
実行結果OUTPUT
2:ERROR disk full
ERROR disk full

一致する行がない場合、grepは終了ステータス1を返します。これは検索結果が空という意味で、必ずしもスクリプト全体の異常ではありません。用途に応じて扱いを決めます。

04

ファイルを一行ずつ読む

行単位のデータを安全に処理する基本形は、while IFS= read -r lineです。入力リダイレクトを使うと、標準入力からファイルを読み込めます。

ログを番号付きで表示BASH
line_number=0
while IFS= read -r line; do
    ((line_number++))
    printf '%02d: %s\n' "$line_number" "$line"
done < data/app.log
実行結果OUTPUT
01: INFO start
02: ERROR disk full
03: INFO finish

IFS=は行頭・行末の空白を保ち、read -rはバックスラッシュをそのまま扱います。データを壊さず読むための定型として覚えましょう。

05

パイプで集計する

複数のコマンドをパイプでつなぐと、検索、抽出、並べ替え、集計を段階的に書けます。

ログの種類を集計COMMAND
cut -d' ' -f1 data/app.log | sort | uniq -c
実行結果OUTPUT
      1 ERROR
      2 INFO

cut -d' ' -f1は空白区切りの1列目を取り出します。sortで同じ値を隣り合わせにしてからuniq -cで数えます。入力に連続空白がある場合は、awkなど別の方法が適することもあります。

awkで条件と列を指定COMMAND
awk '$1 == "ERROR" { print NR, $0 }' data/app.log
実行結果OUTPUT
2 ERROR disk full

NRは行番号、$0は行全体です。テキスト処理は入力形式に強く依存するため、実際のデータを数行確認してから使います。

06

練習:エラーログを保存する

data/app.logからERRORを含む行だけをdata/errors.logへ保存し、保存した件数を表示してください。

解答例BASH
grep 'ERROR' data/app.log > data/errors.log || true
count=$(wc -l < data/errors.log)
printf 'エラー: %s件\n' "$count"
cat data/errors.log
実行結果OUTPUT
エラー: 1件
ERROR disk full

次は関数と引数へ進み、処理を再利用できる形へ整理します。