http://qs1969.pair.com?node_id=551228

perlknight has asked for the wisdom of the Perl Monks concerning the following question:

All, I have the following line:
k4J37P420342 3256 10021545 May 18 23:07 MAILER-DAEMON (Deferred: Connection reset by somdomain.com.) <someone@somedomain.com>
I want to generate a list that looks like(only with line starting that has MAILER-DAEMON:
k4J37P420342 someone@somedomain.com etc...
Any idea? Thanks.

Replies are listed 'Best First'.
Re: hashing out lines from mailq...
by GrandFather (Saint) on May 23, 2006 at 20:25 UTC

    Using a regex probably does it for you. Matching the parenthasised stuff ("(Deferred: ...)") may be problematic if nested parenthesis are allowed. That aside, the following should get you started:

    use warnings; use strict; my $str = 'k4J37P420342 3256 10021545 May 18 23:07 MAILER-DAEMON + (Deferred: Connection reset by somdomain.com.) <someone@somedomain.c +om>'; my ($code, $addr) = $str =~ /(\S+)(?:[^)]*)\)\s*<([^>]+)/; print "$code $addr\n" if defined $addr;

    Prints:

    k4J37P420342 someone@somedomain.com

    DWIM is Perl's answer to Gödel
      here's the the code, the regex for Deferred is working now, but still I am running out of idea how store multiple recipients associating with the qid, any idea?
      #!/usr/bin/perl use Data::Dumper; open (Q,"-|" , "cat mailqout" ); my $ref_tomailq= []; my $coutner = 0; my $temp_qid; while(<Q>) { # Ignore the banners and totals next if m{ Q-ID }ix ; # Ignore any completed jobs #next if m{ ^ .{10,20} \s \(job \s completed\) }x; if( m{ ^\w+ }ix ) { my @ar_line = split(/\s+/,$_); my $num_char = length($ar_line[0]); if ( $num_char > "0") { #print "$ar_line[$counter] $ar_line[-1]"; $ref_tomailq->[$counter]->{$ar_line[0]}->{"fro +m"} = $ar_line[-1]; $temp_qid = $ar_line[0]; $counter++; } } else { my @ar_line = split(/\s+/, $_); chomp(@ar_line); if ( $ar_line[1] =~ /\(Deferred:/) { $ref_tomailq->[$counter-1]->{$temp_qid}->{"sta +tus"} = "deffered"; } elsif ($ar_line[1] =~ /<{1}\w+>?/) { #print "@ar_line\n"; $ref_tomailq->[$counter-1]->{$temp_qid}->{"to" +} = $ar_line[1] } } } print Dumper($ref_tomailq);
      Thanks.

        The code I showed you does that.

        /J\

Re: hashing out lines from mailq...
by gellyfish (Monsignor) on May 24, 2006 at 07:39 UTC

    This is a dumb brute-force parser for the output of mailq. If you just want to get the messages from MAILER-DAEMON you can check $entry->{from} when you are iterating over @entries:

    my $header = 1; my @entries; my $entry = {}; while(<>) { if ($header) { $header = 0 if /^--/; next; } if (/^(\S+)\s+(\d+)\s+(.+?)\s+<?(\S+)>?/) { push @entries, $entry if exists $entry->{msg_id}; $entry = {}; $entry->{msg_id} = $1; $entry->{size} = $2; $msg->{date} = $3; $msg->{from} = $4; } elsif (/\s+\((.*)\)/) { $entry->{message} = $1; } elsif ( /\s+<(.*)>?/ ) { $entry->{recipients} = [] unless exists $entry->{recipients}; push @{$entry->{recipients}}, $1; } } push @entries, $entry if exists $entry->{msg_id}; foreach $entry ( @entries ) { print $entry->{msg_id}, join " ", @{$entry->{recipients}},"\n"; }

    /J\

      Thanks. How would I go about geting the following for all deferred messages: qid, from, all recipients? Is there a better way of doing this besides parsing the output of mailq with regex? Thanks.

        That code does it, you just have to look for 'Defered' in $entry->{message}. The only other alternative (for sendmail at least) is to parse all of the 'q' files in /var/spool/mqueue, which will almost certainly by more of a pain.

        /J\

Re: hashing out lines from mailq...
by Fletch (Bishop) on May 23, 2006 at 20:19 UTC

    Yeah, write some perl that pulls out the first item on the first line and the last on the third line and then prints them out.

    (Hint: Include more code and you'll get more helpful responses. See also How (Not) To Ask A Question)

      O.K, here's the code, what I am looking for is to be able to associated qid to from,to field of messages with deffered status.
      #!/usr/bin/perl use Data::Dumper; open (Q,"-|" , "cat mailqout" ); my $ref_tomailq= []; my $coutner = 0; my $temp_qid; while(<Q>) { # Ignore the banners and totals next if m{ ^ ( -----Q-ID----- | \s* / \S+ / | \s+ Total \s req +uests: | \ S+ \s+ Queue \s+ status ) }ix; # Ignore any completed jobs next if m{ ^ .{10,20} \s \(job \s completed\) }x; if( m{ ^\w+ }ix ) { my @ar_line = split(/\s+/,$_); my $num_char = length($ar_line[0]); if ( $num_char > "0") { print "$ar_line[$counter] $ar_line[-1]"; $ref_tomailq->[$counter]->{$ar_line[0]}->{"fro +m"} = $ar_line[-1]; $temp_qid = $ar_line[0]; $counter++; } } else { my @ar_line = split(/\s+/, $_); if ($ar_line[1] =~ /Deffered:/) { next; } elsif ($ar_line[1] =~ /<{1}\w+>?/) { #my @ar_email = split(/\s+/, $_); chomp(@ar_line); print "@ar_line\n"; $ref_tomailq->[$counter-1]->{$temp_qid}->{"to" +} = $ar_line[1] } } } print Dumper($ref_tomailq);
      output of dumper:
      $VAR1 = [ { 'k4NDsM423484' => { 'to' => '<distribution@abc.com>', 'from' => '<support@abc.com>' } } ];
      This is fined if there is only one recipient, but does not work well with multiple recipient. How can I it in this format?:
      $VAR1 = [ { 'k4NDsM423484' => { 'to' => {'<distribution@abc.com>','noc +@abc.com' } 'from' => '<support@abc.com>' } } ];
      or
      $VAR1 = [ { 'k4NDsM423484' => { 'to' => ['<distribution@abc.com>','noc +@abc.com' ] 'from' => '<support@abc.com>' } } ];
      Any idea thanks.
Re: hashing out lines from mailq...
by hsinclai (Deacon) on Jan 10, 2010 at 17:16 UTC
    For a quick list, this is working as a one liner from the linux shell (mailq from the sendmail.postfix binary)..
    mailq | perl -lane '$/=q[]; print $F[0].q[ ].$F[$#F].$/ unless /^-/;'
    I know that mailq output varied a bit by platform..
    -Harold