我有一个包含大量行的日志文件,其中每个行由空行分隔。我想从每一行grep某些行(包含常见模式)。每一行都是关于邮件的。示例日志文件如下:
#START#
03:48:19:798: : <23/08/2012 03:48:19:019>
03:48:19:798: : <---23/08/2012 03:48 --->
03:48:19:799: : MAIL FROM IP=1.2.3.4
03:48:19:799: : START CHECKING OF IPLIMIT
03:48:19:799: : STOP CHECKING OF IPLIMIT
03:48:20:848:In : MAIL FROM: <a@abc.com>
03:48:20:848: : [A:A:A]
03:48:20:849: : max attach size-->5242880
03:48:20:856: : User Is Authenticated with "a@abc.com and domain abc.com"
03:48:20:856: : Passed
03:48:20:987:In : RCPT TO: <x@xyz.com>
03:48:20:987: : email x@xyz.com
03:48:20:992: : [A:A:A]
03:48:20:999: : passed
03:48:20:999:Inside the Store Mails
03:48:20:999: : BCC feature is not applicable x@xyz.com
03:48:21:000: : BCC feature is not applicable from a@abc.com
03:48:21:000:Inside the Store
03:48:21:132:In : RCPT TO: <y@xyz.com>
03:48:21:132: : email y@xyz.com
03:48:21:133: : [A:A:A]
03:48:21:140: : passed
03:48:21:140:Inside the Store Mails
03:48:21:140: : BCC feature is not applicable y@xyz.com
03:48:21:140: : not authenticated
03:48:21:140:Inside the Store
03:48:21:271: : Data Received
03:50:32:049: : 552 Size Limit Exceeded(5242880)
03:50:32:049: : File Moved in LargeSize Folder....
03:50:32:049: : File Moved in LargeSize Folder....
03:50:32:049: : Connection closed
03:50:32:049: : File Deleted /home/Mail//mailbox/LargeSize/x@xyz.com:24085.444724474357(1345673901000)
03:50:32:051: : File Deleted /home/Mail//mailbox/LargeSize/y@xyz.com:39872.512978520455(1345673901140)
MAIL DATA : : 6815779 Bytes
Total: Conn : 16713 Quit By Host : 5565 Stored : 11134 Loop:0
#END#
W A R N I N G ---------------W A R N I N G
...Waiting for activity on port Total Thread Started & 16732 Stoped 16730
#START#
03:56:20:790: : <23/08/2012 03:56:20:020>
03:56:20:790: : <---23/08/2012 03:56 --->
03:56:20:791: : MAIL FROM IP=2.3.4.5
03:56:20:792: : IP IS FRIEND IN WHITELIST
03:56:20:834:In : MAIL FROM:<y@xyz.com>
03:56:20:834: : [A:A:A]
03:56:20:834: : null
03:56:20:834: : Passed
03:56:20:834:In : RCPT TO: <a@abc.com>
03:56:20:834: : email a@abc.com
03:56:20:835: : Mailing List
03:56:20:835: : [A:A:A]
03:56:20:836: : passed
03:56:20:836: : Proceesing maillist
03:56:20:839: : Data Received
03:56:20:865: : /home/Mail//mailbox/MailingList/a@abc.com:79602.39544573233(1345674380836) Msg Queued For Delivery
03:56:20:865: : Msg forward successfully
03:56:20:865: : /home/Mail//mailbox/MailingList/M14310.39892966699(1345674380837) Msg Queued For Delivery
MAIL DATA : : 27985 Bytes
Total: Conn : 16732 Quit By Host : 5582 Stored : 11135 Loop:0
#END#
...Waiting for activity on port Total Thread Started & 16735 Stoped 16731
#START#
03:56:23:957: : <23/08/2012 03:56:23:023>
03:56:23:957: : <---23/08/2012 03:56 --->
03:56:23:958: : MAIL FROM IP=2.3.4.5
03:56:23:959: : IP IS FRIEND IN WHITELIST
03:56:23:999:In : MAIL FROM: <x@xyz.com>
03:56:23:999: : [A:A:A]
03:56:23:999: : null
03:56:23:999: : Passed
03:56:23:999:In : RCPT TO: <y@xyz.com>
03:56:23:999: : email y@xyz.com
03:56:24:000: : [A:A:A]
03:56:24:007: : passed
03:56:24:008:Inside the Store Mails
03:56:24:009: : BCC feature is not applicable y@xyz.com
03:56:24:009: : not authenticated
03:56:24:009:Inside the Store
03:56:24:009: : Data Received
03:56:24:053: : /home/Mail//mailbox/External/y@xyz.com:50098.70335800691(1345674384009) Msg Queued For Delivery
03:56:24:054: : Msg forward successfully
MAIL DATA : : 28276 Bytes
Total: Conn : 16735 Quit By Host : 5582 Stored : 11136 Loop:0
#END#
此处,a @ abc.com是外部邮件ID,x @ xzz.com,y @ xyz.com是内部邮件ID。 对于每封邮件,都会生成从#START#到#END#的一堆行。
从每一行我想运行一些模式匹配。我只想要那些邮件从内部电子邮件ID到外部电子邮件ID(第二串)的邮件。
我不希望邮件从外部电子邮件地址/ ID到内部电子邮件ID(第1行),或者从内部电子邮件ID到内部电子邮件ID。 (第3串)。
在我拥有邮件从内部到外部的一堆行之后,我想提取包含单词FROM
和TO
的行。
我尝试使用awk的RS
,ORS
,FS
和OFS
个变量来转换从#START#
开始到结束的每一行制作单行记录,但不能。我无法通过|
或~
等分隔符替换换行符。此外,我现在不知道如何在每个资源记录上运行多个模式匹配。
我尝试使用/PATTERN/
选项,但是后来无法使用system()
函数运行grep命令来获取检查域名的行。它给了我错误:sh: 1: not found
。无法突破它。我用了代码:
if ($0 ~ /FROM/) { print $0 | system("egrep -i 'FROM|TO'") }
此外,如果我尝试使用以下类型的代码导出每个记录,它不起作用:
for i in $(cat log_file | awk_file_givin_1_resource_record_at_a_time) ; do pattern_matching_commands ; done
这不起作用,因为模式匹配一次只能在一条线上工作,而我希望它一次可以在整个线上工作。
答案 0 :(得分:2)
如果记录之间始终有空行,并且记录中永远不是空行,请使用awk的“段落模式”:将RS
设置为空字符串。
awk -v RS= '
/^[0-9:]*In : MAIL FROM: <[^<>]*@example\.com>$/ &&
/^[0-9:]*In : RCPT TO: <[^<>]*@example\.com>$/ { … }
'
如果您确实需要使用#START#
和#END#
标记,请随时在变量中累积数据。当您到达#END#
时,处理然后重置变量。如果需要,禁用处理直到下一个#START#
。
BEGIN { in_record = 1; }
/^#START#$/ { in_record = 1; }
!in_record { next; }
/^[0-9:]*In : MAIL FROM: <([^<>]*)>$/ { from = $0; sub(/.*</, "", from); sub(/>.*/, "", from); }
…
/^#END#$/ {
/* processing goes here */
from = "";
in_record = 0;
}
答案 1 :(得分:2)
我认为以下BASH脚本运行良好,但您应该根据日志大小对其进行基准测试:
#!/bin/bash
INTERNAL_DOMAINS="${1:-xyz.com|xyz.net}"
declare -i LINES BYTES VALIDS
LINES=0
BYTES=0
VALIDS=0
STATUS=stopped
while read LINE
do
if [ "$STATUS" = stopped ]
then
if [ "${LINE:0:7}" = "#START#" ]
then
STATUS=started
PARA=""
fi
else
if [ "${LINE:0:5}" = "#END#" ]
then
if [ $STATUS = valid ]
then
VALIDS+=1
echo "$PARA" | egrep -w "FROM|TO"
echo -e "$VALIDS matched\t----------------------------------------"
fi
STATUS=stopped
elif (echo "$LINE" | fgrep -q "RCPT TO") && (echo "$LINE" | egrep -qiv "@($INTERNAL_DOMAINS)")
then
STATUS=valid
PARA+="$LINE
"
else
PARA+="$LINE
"
fi
fi
LINES+=1
BYTES+=${#LINE}
BYTES+=1
echo -en "\rRead: lines: $LINES | kB: $(($BYTES/1024)) | matches: $VALIDS " >&2
done
您应该将上面的脚本设置为可执行文件并像这样运行以获得进度输出:
time ./filter.sh "one.int.com|two.int.com" < sample.log > report.out