2008-10-02 159 views
5

在这里,我们正在研究客户可以使用的通讯系统。作为一名实习生,我的一项工作就是帮助拼图的小部分。在这种情况下,我需要做的是扫描电子邮件服务器的日志以获取退回的邮件,并将电子邮件和电子邮件被退回的原因添加到“错误的电子邮件数据库”中。如何在列表中拆分管道分隔的字符串?

坏邮件表有两列:“电子邮件”和“理性” 我用下面的语句来从日志中的信息,并将其发送到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 

如果你有sugestions关于更高效的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; 
+0

你不需要grep和awk。如果您只能提供/var/log/exim/main.log内容的示例,我们可以更好地帮助您构建一个执行grep和awk所做任何事情的perl脚本。 – bmdhacks 2008-10-02 22:26:49

+0

我认为用Perl编写整个代码会更好。你可能会看到速度提升,因为Perl必须重新编译每行代码。 – 2009-01-08 02:41:46

回答

13

像这样的工作:

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。

7

我不知道你想放在@list?如果awk管道每行一行,那么您将在$ line中拥有该行,并且您不需要@list上的for循环。

这就是说,如果你打算把它转换成Perl,为什么还要首先考虑grep和AWK?有关DBI

#!/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 
} 

旁注呼吁:你应该使用占位符,这样一个“坏电子邮件”将无法SQL注入到你的数据库。

+0

+1 ...伟大的思想家认为一样zigdon ;-) – toolkit 2008-10-02 22:28:37

+1

看看分裂的第三个参数作为简化这种方法。 – dland 2008-10-03 12:29:48

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's comment为进一步优化:-)

希望这有助于?

+0

您可以分割(/ /,$ _,22)以便在第22个空格后停止分割。这避免了之后必须分割@fields。 – dland 2008-10-03 12:29:03

3
my(@list) = split /\|/, $line; 

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

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

美元的正则表达式可以说是多余的,而且文件“行尾”。

5

您是否考虑过使用App::Ack代替?不用去掉外部程序,你可以用Perl代替。不幸的是,您必须仔细阅读ack程序代码才能真正了解如何执行此操作,但是您应该获得更便携的程序。