実行ログを出力するシェルスクリプトというのは大抵以下のような形をしています。
# 変数定義Log=/var/log/batch.log
# メイン処理echo 処理開始 >>$Log
...
ちゃんと作るのであればログ出力などの一般的な処理は分割されていることが普通だと思いますが、ここでは単体のスクリプトの中にログ出力処理が実装されている場合を考えます。
さて、上記のままでは、バッチ処理が実行されるたびに延々と同じファイルにログを追記し続けることになり、ファイルはどんどん肥大化していきます。ログが肥大化すると管理しづらくなるので、あるタイミングでログをbatch.log_20191130
のように別名に変更(ローテーション)したくなります。ローテーションする条件は色々ありますが、今回は日付が変わったタイミングとしました。
ここで問題となったのは、バッチ処理が日付をまたぐ可能性があるという点でした。一連の実行ログは同じファイルに出力されていると見返すときに都合が良いですが、日付が変わった瞬間にローテーションしてしまうと実行ログが別々のファイルに分割されてしまいます。逆に、日付が変わってから十分に時間が経ってからローテーションすると、当日実行されたバッチ処理のログが前日分のファイルに混ざることなります。
この問題を解決するためには、「バッチ処理の開始日付」と「実行ログファイルの作成日付」を比較し、両者が同じであればログファイルに追記し、異なっていればローテーションを実行してから新しいログファイルを作成するのが良いと考えました。
バッチ処理の開始日付を得るには date
の実行結果を利用しますが、後で比較がしやすいようにフォーマットを明示的に指定します。%F
を指定するとISO形式(YYYY-MM-DD)の日付を得ることができます。
$TODAY=$(date +%F)# YYYY-MM-DD
一方で、実行ログファイルの日付は ls -l
で取得できます。これも比較しやすいようにフォーマットを指定します。--time-style=long-iso
でISO形式(YYYY-MM-DD)の日付を得ることができます。ただし、ls
が既定で出力する日付は更新日付なので、作成日付を得るために -c
を指定します。
$FILE_CREATION_TIME=$(ls-lc--time-style=long-iso $Log | cut-d' '-f6)# YYYY-MM-DD
一般的(?)に日時の比較は面倒ですが、今回は日付が同一かどうかなので簡単です。
if[$FILE_CREATION_TIME!=$TODAY];then# もしログファイルの作成日付が実行日付と異なるならローテーションmv$Log$Log_$FILE_CREATION_TIMEfi
この数行を、バッチ処理の前に書いておくことで、実行ログのローテーションが上手くできると思います。
もし、$Log_$FILE_CREATION_TIME
が既に存在する場合は、ローテーションに失敗しつづけるので気をつける必要があります。
以上