7

在工作中,我们正在开发一个客户可以使用的时事通讯系统。作为实习生,我的工作之一是帮助解决较小的难题。在这种情况下,我需要做的是扫描电子邮件服务器的日志以查找退回的邮件,并将电子邮件和电子邮件退回到“错误电子邮件数据库”的原因添加。

bad emails 表有两列:'email' 和 'reason' 我使用以下语句从日志中获取信息并将其发送到 Perl 脚本

grep " 550 " /var/log/exim/main.log | awk '{print $5 "|" $23 " " $24 " " $25 " " $26 " " $27 " " $28 " " $29 " " $30 " " $31 " " $32 " " $33}' | perl /devl/bademails/getbademails.pl

如果您对更高效的 awk 脚本有建议,那么我也会很高兴听到这些建议,但我主要关注的是 Perl 脚本。awk 通过管道将“foo@bar.com|reason forbounce”传送到 Perl 脚本。我想接收这些字符串,将它们拆分为 | 并将两个不同的部分放入数据库中各自的列中。这是我所拥有的:

#!usr/bin/perl                                                                                                                                                                               

use strict;
use warnings;
use DBI;

my $dbpath = "dbi:mysql:database=system;host=localhost:3306";
my $dbh = DBI->connect($dbpath, "root", "******")
    or die "Can't open database: $DBI::errstr";

while(<STDIN>) {
    my $line = $_;                                    
    my @list = # ?  this is where i am confused
    for (my($i) = 0; $i < 1; $i++)
    {
        if (defined($list[$i]))
        {
            my @val = split('|', $list[$i]);
            print "Email: $val[0]\n";
            print "Reason: $val[1]";
            my $sth = $dbh->prepare(qq{INSERT INTO bademails VALUES('$val[0]', '$val[1]')});
            $sth->execute();                                                                                                  
            $sth->finish();                                                                                                                                                                              
        }
    }
}
exit 0;
4

5 回答 5

14

像这样的东西会起作用:

while(<STDIN>) {
  my $line = $_;
  chomp($line);
  my ($email,$reason) = split(/\|/, $line);
  print "Email: $email\n";
  print "Reason: $reason";
  my $sth = $dbh->prepare(qq{INSERT INTO bademails VALUES(?, ?)});
  $sth->execute($email, $reason);                                                                                                  
  $sth->finish();                                                                                                                                                                              
}

您可能会发现在 Perl 中完成所有事情会更容易。"next unless / 550 /" 可以替换 grep,而正则表达式可能会替换 awk。

于 2008-10-02T22:28:58.907 回答
7

我不确定你想在@list 中添加什么?如果 awk 对每个条目进行管道传输,那么您将在 $line 中拥有它,并且您不需要 @list 上的 for 循环。

也就是说,如果您要将它通过管道传输到 Perl 中,为什么要首先使用 grep 和 AWK?

#!/ust/bin/perl -w
use strict;

while (<>) {
  next unless / 550 /;
  my @tokens = split ' ', $_;
  my $addr = $tokens[4];
  my $reason = join " ", @tokens[5..$#tokens];

  # ... DBI code
}

关于 DBI 调用的旁注:您应该真正使用占位符,以便“坏电子邮件”无法将 SQL 注入您的数据库。

于 2008-10-02T22:25:08.260 回答
5

为什么不放弃 grep 和 awk 而直接使用 Perl?

免责声明:我没有检查以下代码是否编译:

while (<STDIN>) {
    next unless /550/; # skips over the rest of the while loop
    my @fields = split;
    my $email = $fields[4];
    my $reason = join(' ', @fields[22..32]);
    ...
}

编辑:请参阅@dland 的评论以获得进一步的优化:-)

希望这可以帮助?

于 2008-10-02T22:25:33.563 回答
5

您是否考虑过使用App::Ack代替?您可以只使用 Perl,而不是使用外部程序。不幸的是,您必须通读ack程序代码才能真正了解如何执行此操作,但是您应该得到一个更便携的程序。

于 2008-10-03T06:44:41.743 回答
4
my(@list) = split /\|/, $line;

如果行尾有额外的管道符号,这将在 @list 中生成两个以上的条目。为避免这种情况,请使用:

$line =~ m/^([^|]+)\|(.*)$/;
my(@list) = ($1, $2);

正则表达式中的美元可以说是多余的,但也记录了“行尾”。

于 2008-10-02T22:35:07.723 回答