如何在列表中分割用竖线分隔的字符串?
在工作中,我们正在开发供客户使用的新闻通讯系统。作为实习生,我的工作之一是帮助解决小难题。在这种情况下,我需要做的是扫描电子邮件服务器的日志中是否存在退回邮件,并将电子邮件及其退回原因添加到"不良电子邮件数据库"中。
错误的电子邮件表具有两列:"电子邮件"和"原因"
我使用以下语句从日志中获取信息,并将其发送到Perl脚本
grep " 550 " /var/log/exim/main.log | awk '{print "|" " " " " " " " " " " " " " " " " " " " " }' | perl /devl/bademails/getbademails.pl
如果我们对更有效的awk脚本有疑问,那么我也很高兴听到这些提示,但是我的主要重点是Perl脚本。 awk将" [email protected] |反弹的原因"传送到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;
解决方案
我不确定我们要在@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注入到数据库中。
为什么不放弃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的评论以进行进一步的优化:-)
希望这可以帮助?
这样的事情会起作用:
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中完成整个操作会更容易。 "下一步,除非/ 550 /"可以替换grep,而正则表达式则可以替换awk。
my(@list) = split /\|/, $line;
如果在行尾有多余的管道符号,这将在@list中生成两个以上的条目。为避免这种情况,请使用:
$line =~ m/^([^|]+)\|(.*)$/; my(@list) = (, );
正则表达式中的美元可以说是多余的,但是也记录了"行尾"。
我们是否考虑过改用App :: Ack?除了可以使用外部程序,我们还可以使用Perl。不幸的是,我们必须通读ack程序代码才能真正了解如何执行此操作,但是因此我们应该获得一个更可移植的程序。