我正在编写一个 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
谢谢。
我会通过存储当前消息的行来处理它,当消息结束时,如果没有
INF
看到标记,则打印存储的批次。这里,d
保存当前消息的行(d 代表数据),p
告诉我们是否要打印存储的行。这里的第一条规则匹配时间戳行,如果
p
为真,则打印任何存储的行,存储该行并设置p
为一个。如果看到p
带有模式的线,第二条规则将重置为零;info
模式设置为带有 的变量-vinfo=...
。第三条规则将当前行附加到收集的那些行,END
如果设置了,则该规则再次只打印收集的行p
。我们也可以这样写,这也会
info
在时间戳行上检查模式:一般来说,用
awk
或 Perl 编写这样的东西可能是个好主意。结果至少比一个 shell 脚本运行起来要快得多,shell 脚本分叉了 、 等的几十grep
个awk
副本cut
...