7

ここでは、クライアントが使用できるニュースレター システムに取り組んでいます。インターンとしての私の仕事の 1 つは、パズルの小さなピースを手伝うことです。この場合、私がする必要があるのは、メールサーバーのログをスキャンしてバウンスされたメッセージを探し、メールと、メールが「悪いメールデータベース」にバウンスした理由を追加することです。

悪いメール テーブルには、「メール」と「理由」の 2 つの列があります。次のステートメントを使用して、ログから情報を取得し、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 スクリプトにパイプします。これらの文字列を取り込み、| で分割します。2 つの異なる部分をデータベースのそれぞれの列に入れます。ここに私が持っているものがあります:

#!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 until / 550 /」は grep を置き換えることができ、正規表現はおそらく awk を置き換えることができます。

于 2008-10-02T22:28:58.907 に答える
7

@list に何を入れたいのかわからない? awk がエントリごとに 1 行をパイプ処理する場合、それは $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

代わりにApp::Ackの使用を検討しましたか?外部プログラムにシェルアウトする代わりに、代わりにPerlを使用することができます。残念ながら、これを行う方法を実際に理解するには、 ackプログラムコードを読む必要がありますが、結果として、より移植性の高いプログラムを入手する必要があります。

于 2008-10-03T06:44:41.743 に答える
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 に答える
4
my(@list) = split /\|/, $line;

行の末尾に余分なパイプ記号がある場合、これにより @list に 3 つ以上のエントリが生成されます。それを避けるには、次を使用します。

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

正規表現のドルは間違いなく不必要ですが、「行末」も文書化しています。

于 2008-10-02T22:35:07.723 に答える