Сделайте это за один проход:
#! /usr/bin/perl
use warnings;
use strict;
# for demo only
*ARGV = *DATA;
my %msg;
while (<>) {
if (s!^.*postfix/\w+\[.+?\]: (\w+):\s*!!) {
my $key = $1;
push @{ $msg{$key}{$1} } => $2
while /\b(to|from|client)=(.+?)(?:,|$)/g;
}
}
use Data::Dumper;
$Data::Dumper::Indent = 1;
print Dumper \%msg;
__DATA__
Apr 8 14:22:02 MailSecure03 postfix/smtpd[32388]: BA1CE38965: client=mail.example.com[x.x.x.x]
Apr 8 14:22:03 MailSecure03 postfix/cleanup[32070]: BA1CE38965: message-id=<49dc4d9a.6020...@example.com>
Apr 8 14:22:03 MailSecure03 postfix/qmgr[19685]: BA1CE38965: from=<mailt...@example.com>, size=1087, nrcpt=2 (queue active)
Apr 8 14:22:04 MailSecure03 postfix/smtp[32608]: BA1CE38965: to=<us...@test.com>, relay=127.0.0.1[127.0.0.1]:10025, delay=1.7, delays=1/0/0/0.68, dsn=2.0.0, status=sent (250 OK, sent 49DC509B_360_15637_162D8438973)
Apr 8 14:22:04 MailSecure03 postfix/smtp[32608]: BA1CE38965: to=<us...@test.com>, relay=127.0.0.1[127.0.0.1]:10025, delay=1.7, delays=1/0/0/0.68, dsn=2.0.0, status=sent (250 OK, sent 49DC509B_360_15637_162D8438973)
Apr 8 14:22:04 MailSecure03 postfix/qmgr[19685]: BA1CE38965: removed
Apr 8 14:22:04 MailSecure03 postfix/smtpd[32589]: 62D8438973: client=localhost.localdomain[127.0.0.1]
Apr 8 14:22:04 MailSecure03 postfix/cleanup[32080]: 62D8438973: message-id=<49dc4d9a.6020...@example.com>
Apr 8 14:22:04 MailSecure03 postfix/qmgr[19685]: 62D8438973: from=<mailt...@example.com>, size=1636, nrcpt=2 (queue active)
Apr 8 14:22:04 MailSecure03 postfix/smtp[32417]: 62D8438973: to=<us...@test.com>, relay=y.y.y.y[y.y.y.y]:25, delay=0.19, delays=0.04/0/0.04/0.1, dsn=2.6.0, status=sent (250 2.6.0 <49dc4d9a.6020...@example.com> Queued mail for delivery)
Apr 8 14:22:04 MailSecure03 postfix/smtp[32417]: 62D8438973: to=<us...@test.com>, relay=y.y.y.y[y.y.y.y]:25, delay=0.19, delays=0.04/0/0.04/0.1, dsn=2.6.0, status=sent (250 2.6.0 <49dc4d9a.6020...@example.com> Queued mail for delivery)
Apr 8 14:22:04 MailSecure03 postfix/qmgr[19685]: 62D8438973: removed
Код работает, сначала ища идентификатор очереди ( например, , BA1CE38965
и 62D8438973
выше), который мы храним в $key
.
Далее мы находим все совпадения в текущей строке (благодаря переключателю /g
), которые выглядят как to=<...>
, client=mail.example.com
и т. Д., С разделительной запятой и без нее.
Обратите внимание на шаблон
\b
- совпадения только на границе слова (предотвращает сопоставление xxxto=<...>
)
(to|from|client)
- совпадение to
или from
или client
(.+?)
- сопоставляет значение поля с не жадным квантификатором
(?:,|$)
- соответствует запятой или в конце строки без ввода в $3
Нежадный (.+?)
заставляет матч останавливаться на первой запятой, с которой он сталкивается, а не на последней. В противном случае на линии с
to=<foo@example.com>, other=123
вы получите <foo@example.com>, other=123
в качестве получателя!
Затем для каждого совпавшего поля мы push
помещаем его в конец массива (например, поскольку может быть несколько получателей), подключенного как к идентификатору очереди, так и к имени поля. Посмотрите на результат:
$VAR1 = {
'62D8438973' => {
'client' => [
'localhost.localdomain[127.0.0.1]'
],
'to' => [
'<us...@test.com>',
'<us...@test.com>'
],
'from' => [
'<mailt...@example.com>'
]
},
'BA1CE38965' => {
'client' => [
'mail.example.com[x.x.x.x]'
],
'to' => [
'<us...@test.com>',
'<us...@test.com>'
],
'from' => [
'<mailt...@example.com>'
]
}
};
Теперь предположим, что вы хотите напечатать всех получателей сообщения, чей идентификатор очереди BA1CE38965
:
my $queueid = "BA1CE38965";
foreach my $recip (@{ $msg{$queueid}{to} }) {
print $recip, "\n":
}
Может быть, вы хотите знать только, сколько получателей:
print scalar @{ $msg{$queueid}{to} }, "\n";
Если вы хотите предположить, что каждое сообщение имеет только одного клиента, откройте его с помощью
print $msg{$queueid}{client}[0], "\n";