2021.02.18  

【bash】コマンドラインでwhile文とif文を使ったcronログの日時判定を行う

Linux    

シェルじゃなくてコマンドラインで処理したい

製品やツールの仕様上、シェルではなくてコマンドラインで複雑な処理をしたい場合がある。
そういった場合のコマンドの書き方について記載する。環境はCentOS7。

作成したコマンド

こちらは直近のcronログが10分以内に出力されていなければOK、出力されていればNGを出すコマンド。少しややこしので、コマンドの詳細を次の項で解説する。
見やすさのため、コマンドにバックスペースを入れて改行しているが、もちろんバックスペースを消して一行のコマンドとすることも可能。

実行コマンド
$ tail -10 /var/log/cron | awk '{print $1" "$2" "$3}' | \
while read line; do \
if [ $((`date +%s` - `date -d "$line" +%s`)) -gt 600 ];then \
echo "OK";else echo "NG";fi; \
done
/var/log/cron の内容(インプット)
Feb 18 07:01:01 ip-172-26-8-203 CROND[5544]: (root) CMD (run-parts /etc/cron.hourly)
Feb 18 07:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[5544]: starting 0anacron
Feb 18 07:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[5553]: finished 0anacron
Feb 18 08:01:01 ip-172-26-8-203 CROND[10973]: (root) CMD (run-parts /etc/cron.hourly)
Feb 18 08:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[10973]: starting 0anacron
Feb 18 08:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[10982]: finished 0anacron
Feb 18 09:01:01 ip-172-26-8-203 CROND[12351]: (root) CMD (run-parts /etc/cron.hourly)
Feb 18 09:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[12351]: starting 0anacron
Feb 18 09:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[12360]: finished 0anacron
Feb 18 10:01:01 ip-172-26-8-203 CROND[13748]: (root) CMD (run-parts /etc/cron.hourly)
Feb 18 10:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[13748]: starting 0anacron
Feb 18 10:01:02 ip-172-26-8-203 run-parts(/etc/cron.hourly)[13757]: finished 0anacron
Feb 18 11:01:01 ip-172-26-8-203 CROND[15126]: (root) CMD (run-parts /etc/cron.hourly)
Feb 18 11:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[15126]: starting 0anacron
Feb 18 11:01:01 ip-172-26-8-203 run-parts(/etc/cron.hourly)[15135]: finished 0anacron
出力結果(アウトプット)
OK
OK
OK
OK
OK
OK
OK
NG
NG 
NG

1. tailの結果をawkに渡す

コマンド
tail -10 /var/log/cron | awk '{print $1" "$2" "$3}' 

まず、直近のログを10件と定義する。
そうした場合、tail -10 [ファイル名] でファイル末尾の10行の文字列を取得できる。

次にawkコマンドにtailの結果を渡す。
awk '{print $1}' とすると渡された行の1列目を抽出し、取得する。
上のインプットで言えば「Feb」が抽出される。
awk '{print $2}' とすると 「18」が抽出される。

それを組み合わせて awk '{print $1" "$2" "$3}' とすると空白区切りで前から3列抽出してくれる。
このコマンドだけを実行すると、以下のようなリストを取得できる。

Feb 18 08:01:01 
Feb 18 09:01:01 
Feb 18 09:01:01 
Feb 18 09:01:01 
Feb 18 10:01:01 
Feb 18 10:01:01 
Feb 18 10:01:02 
Feb 18 11:01:01 
Feb 18 11:01:01 
Feb 18 11:01:01 

2. whileでループする

先ほど抽出したリストをwhile文にinputする。
inputしたリストはline変数に一行ずつ渡され、リストの行の数だけ while read line; do からdone までの処理を繰り返す。

コマンド
while read line; do 処理; 処理; 処理; done

3. if文の定義

while文の中にif文を書ける。普通のif文を一行で書いている。

コマンド
if [ 条件式 ];then  "条件が正の場合の処理";else echo "条件が誤の場合の処理"; fi

4. 10分以上前に出力されたログであればOKを出力し、そうでなければNGを出力する処理

if [ $((`date +%s` - `date -d "$line" +%s`)) -gt 600 ];then \
echo "OK";else echo "NG";fi

date +%s は現在時刻をUNIX時間に変換している。
date -d "$line" +%s はawkコマンドで抽出した時間をUNIX時間に変換している。
bashでは $ (( 計算式 )) とすると、四則演算が行える。(shではできなかったはず)
この結果が600秒以上 < $ (( 計算式 )) -gt 600)> であればOKを出力する。

今の日時が2月18日の11時5分であれば 以下のような出力となる。

$ tail -10 /var/log/cron | awk '{print $1" "$2" "$3}' | \
while read line; do \
if [ $((`date +%s` - `date -d "$line" +%s`)) -gt 600 ];then \
echo "OK";else echo "NG";fi; \
done
OK
OK
OK
OK
OK
OK
OK
NG
NG 
NG

終わりに

もう少し頑張れば、全部OKだった時にOKを一行、それ以外ならNGを一行出力するといった処理も書ける。
あと、awkの出番って意外に多いなと思う今日この頃。インフラ屋さんなら身につけておいて損は無い知識だと再認しました。

コメント
現在コメントはありません。
コメントする
コメント入力

名前 (※ 必須)

メールアドレス (※ 必須 画面には表示されません)

送信