Q1第1引数が渡されなかったときに既定値access.logを使う書き方はどれですか?
ログ集計レポート — 引数・関数・連携の総仕上げ
この記事は、基礎コマンドからシェルスクリプトまでLinuxの実践的なスキルを1からマスターする「Linux入門講座の一部」です。
log=${1:-access.log} で対象ログを受け取り、forループとgrep -c・awk '{sum+=$1}' 連携で集計し、here-docレポートとexitコードにまとめる構成を、図解と端末で実習します。
要素を1本に統合する — ログ集計レポートの骨格
ここまでに学んだ変数・位置パラメータ($1)・条件分岐([ ]とif)・ループ(for / while)・関数(name() { }とlocal)・入力読込(while read … done < file)・コマンド連携($(...))・出力(>>と here-doc)を、1 本の実用スクリプトに組み合わせます。
題材は運用で最も多い「ログ集計レポート」です。
実用スクリプトは、引数で対象ログとしきい値を受け取り、入力チェックをしてから集計し、結果をレポートにまとめ、最後に終了コードを返す流れで組みます。
集計部分はgrepで件数、awkで合計、sedで整形といったコマンドと連携させ、繰り返しは関数とループにまとめると読みやすくなります。
位置パラメータが空のときは既定値${1:-access.log}で補います。
vi mini.sh # エディタで開き、次の内容を書いて :wq で保存
# #!/bin/sh
# log=${1:-access.log} # 引数が無ければ既定値
# count_status() { # 状態コードの件数を返す関数
# grep -c " $1\$" "$log"
# }
# if [ ! -f "$log" ]; then # 入力チェック
# echo "not found: $log" >&2
# exit 1
# fi
# for s in 200 403 500; do # 状態コードごとに集計
# echo "$s : $(count_status $s)"
# done
# exit 0
chmod +x mini.sh
| 要素 | 本スクリプトでの使い所 | 例 |
|---|---|---|
変数name=... | ログ名・出力先・しきい値を 1 か所で管理する | log=${1:-access.log} |
引数$1 / ${1:-既定} | 対象ログとしきい値をコマンドラインから受け取る | limit=${2:-1} |
条件[ -f f ] / if | ログの存在確認・しきい値超過の判定をする | if [ ! -f "$log" ]; then exit 1; fi |
ループfor / while read | 状態コードごとの集計・1 行ずつの読み取り | for s in 200 403 500; do … done |
関数name() { … } | 集計処理を名前付きでまとめ再利用する | count_status() { grep -c " $1\$" "$log"; } |
入力読込while read … < f | ログを 1 行ずつ読み URL ごとに数える | while read line; do … done < "$log" |
連携$(grep -c …) / awk | 件数・合計をコマンド置換で取り込む | n=$(grep -c ' 500$' "$log") |
出力>> / here-doc | 集計値を定型レポートに書き出す | cat > "$out" <<REPORT … REPORT |
入力を読み連携で仕上げる — while read と grep / awk / sed
1 行ずつの細かな処理はwhile read line; do … done < fileで行います。
読み取った各行に対しgrepで絞り込み、awkで列を集計し、sedで表記をそろえる、といった連携を関数の中で組み合わせると、集計ロジックを部品として再利用できます。
sed 's/^GET /[GET] /'のように整形を挟むと、レポートの体裁を統一できます。
仕上げは here-doc で定型レポートに集計値を埋め込み、しきい値を超えたら警告を追記してexit 1、正常ならexit 0を返します。
引数の 2 つ目をしきい値として${2:-100}で受け取り、if [ "$err" -gt "$limit" ]のように数値比較すると、運用で使える判定付きレポートになります。
基礎で学んだgrep / awk / sedを、シェルスクリプトの制御構造の中で連携させるのが集大成です。
vi scan.sh # エディタで開き、次の内容を書いて :wq で保存
# #!/bin/sh
# log=${1:-access.log}
# limit=${2:-1}
# err=$(grep -c ' 500$' "$log") # 500 の件数を連携で取得
# while read line; do # 1 行ずつ読む
# echo "$line" | sed 's/^/log: /' # 整形して表示
# done < "$log"
# if [ "$err" -gt "$limit" ]; then # しきい値で判定
# echo "WARN: too many 500"; exit 1
# fi
# exit 0
chmod +x scan.sh
while readで 1 行ずつ取り込み、grep / awk / sedと連携して判定付きレポートに仕上げます。引数のしきい値で合否を分ける — 集計と終了コードの統合
前半の引数受け取りと集計、後半の判定と終了コードを 1 本にまとめ、運用で使える「合否判定付きレポート」に仕上げます。
第1引数でしきい値を受け取り、grep -cやawkで集計した件数がしきい値以上なら警告としてexit 1、未満なら正常としてexit 0を返します。
呼び出し元はこの終了コードで成否を判定できます。
数値比較の-gtは「より大きい」、-geは「以上」で、しきい値ちょうどの値の扱いが変わります。
実践 2 の[ "$err" -gt "$limit" ]は件数がしきい値と同じだと条件を満たさず、実践 3 の[ "$err" -ge "$limit" ]は同じ値でも警告になります。
境界の合否を決める要なので、用途に合わせて選びます。
-geで比べ、以上なら警告してexit 1、未満なら正常でexit 0を返します。理解度チェック
まずは1問ずつ答えてみましょう。
Q2ファイルを1行ずつ読み取って処理する書き方はどれですか?
Q3しきい値を超えたときに呼び出し元へ異常を伝えるにはどうしますか?