Как я могу разделить разделенную трубкой строку в списке? - PullRequest
6 голосов
/ 03 октября 2008

Здесь, на работе, мы работаем над системой рассылки, которую могут использовать наши клиенты. Как стажер, одна из моих задач - помогать с небольшими частями головоломки. В этом случае мне нужно отсканировать журналы почтового сервера на наличие сообщений о пересылке и добавить электронные письма и причину, по которой электронное письмо перешло в «плохую базу данных электронной почты».

Таблица плохих писем состоит из двух столбцов: «электронная почта» и «причина» Я использую следующий оператор, чтобы получить информацию из журналов и отправить ее сценарию 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| причину отказов" скрипту 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;

Ответы [ 5 ]

13 голосов
/ 03 октября 2008

Примерно так будет работать:

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, если / 550 /" не может заменить grep, а регулярное выражение может заменить awk.

7 голосов
/ 03 октября 2008

Я не уверен, что вы хотите поместить в @list? Если awk направляет по одной строке на каждую запись, вы получите это в строке $, и вам не понадобится цикл for в @ list.

Тем не менее, если вы собираетесь передать его в 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 в вашу базу данных.

5 голосов
/ 03 октября 2008

Рассматривали ли вы вместо этого App :: Ack ? Вместо того, чтобы использовать внешнюю программу, вы можете просто использовать Perl. К сожалению, вам придется прочитать код программы ack , чтобы действительно понять, как это сделать, но в результате вы должны получить более портативную программу.

5 голосов
/ 03 октября 2008

Почему бы не отказаться от 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 для дальнейшей оптимизации: -)

Надеюсь, это поможет?

4 голосов
/ 03 октября 2008
my(@list) = split /\|/, $line;

Это создаст более двух записей в @list, если у вас есть дополнительные символы канала в конце строки. Чтобы избежать этого, используйте:

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

Доллар в регулярном выражении, возможно, является излишним, но также документирует «конец строки».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...