ログファイルを解析して重要なメッセージが見つかった場合は、電子メールを送信するkshスクリプトを作成しています。一部のメッセージは情報提供用なので無視したいと思います。
ログファイルの形式は次のとおりです。
2018-01-24.08.24.35.875675 some text
more text
more text
more text
more text
2018-01-24.08.24.37.164538 some text
more text
more text
INF9999W <-- informational text
more text
2018-01-24.08.24.46.8602545 some text
more text
more text
more text
タイムスタンプはメッセージ区切り文字として扱われ、タイムスタンプはその後のメッセージに属します。 「メッセージテキスト」が表示されるたびにファイルを検索してから、ファイルからメッセージ全体を削除したいと思います(前のタイムスタンプから次のタイムスタンプの直前まで)。
次を使用してその行を削除できるように、前と次のタイムスタンプの行番号を簡単に確認するにはどうすればよいですか?
awk 'NR<'$preceding_ts' || NR >='$following_ts'
私のアプローチは、すべてのタイムスタンプ行をファイルに入れてから、「情報テキスト」行#の前後のタイムスタンプ行が見つかるまでファイルを繰り返すことでした。特に大容量ファイルを扱うときは、作業量が多いようです。より効率的な方法はありますか?
integer inf_line
integer last_ts_line
integer cur_ts
cp $error_log $copy_log
while true
do
inf_line=$(grep -n "INF99999W" $copy_log | head -1 | cut -f1 -d":")
if [[ $inf_line -eq 0 ]]
then
break
fi
grep -n -E "^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]-" $copy_log | cut -f1 -d":" > $ts_lines
last_ts_line=99999999
cat $ts_lines | while read cur_ts
do
if [[ $cur_ts -gt $inf_line && $last_ts_line -lt $inf_line ]]
then
awk 'NR<'$last_ts_line' || NR >='$cur_ts'' $copy_log > $temp_log
cp $temp_log $copy_log
last_ts_line=$cur_ts
break
fi
last_ts_line=$cur_ts
done
if [[ $last_ts_line -lt $inf_line ]]
then
awk 'NR<'$last_ts_line'' $copy_log > $temp_log
cp $temp_log $copy_log
fi
done
ありがとうございます。
答え1
現在のメッセージの行を保存して実装し、メッセージの終わりにマークがない場合は、保存されたINF
バッチを印刷します。ここで、d
現在のメッセージ(dはデータを表す)を保持する行は、保存されたp
行を印刷するかどうかを示します。
awk -vinfo='INF99+' \
'/^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]/ {
if (p) printf "%s", d; d = $0 ORS; p=1; next }
$0 ~ info {p=0}
{d = d $0 ORS}
END {if (p) printf "%s", d}' < log
ここの最初のルールはタイムスタンプ行と一致し、trueの場合は保存された行を印刷し、その行を保存してから1にp
設定します。 2番目の規則は、対応するパターンがあるp
行が表示されている場合は0にリセットされます。パターンが変数に設定されます。 3番目のルールは現在の行を収集された行に追加し、このルールは設定されている場合は収集された行のみを印刷します。p
info
-vinfo=...
END
p
info
タイムスタンプ行のパターンを確認するために、次のように作成することもできます。
awk -vinfo='INF99+' \
'/^20[0-9][0-9]-[0-1][0-9]-[0-3][0-9]/ {
if (p) { printf "%s", d }; d = ""; p=1; }
$0 ~ info {p=0}
{d = d $0 ORS}
END {if (p) printf "%s", d}' < log
通常、awk
PerlやPerlでこのような内容を書くのはおそらく良い考えです。結果は、少なくとも数十のforkなどgrep
のawk
コピーを持つシェルスクリプトよりはるかに高速です。cut