Chern Jian Leaw wrote:
>
> From: Rob Dixon
> >
> > Chern Jian Leaw wrote:
> > >
> > > I have a text file below which is simply an output from the UNIX utility
> > > rpcinfo:
> > >
> > > 100008    1   udp  55734   walld         program 100008 version 1 ready and
> > > waiting
> > > 107374    1   udp  64018   rpcinfo: RPC: Timed out
> > > 100008    1   tcp  55684   sprayd       program 100008 version 1 sleeping
> > >
> > > In the attached script, I'm extracting the lines from the file which does
> > > NOT match the string "ready and waiting". For those lines from the rpcinfo
> > > output which did not match "ready and waiting" string, an e-mail would be
> > > sent out to some respective sys admin.
> > >
> > > In the script, I've obtained the attributes i.e. the program no, version,
> > > protocol, port, and response via pattern matching:
> > > $waiting[$lines]=~m/^(\d+)\s+(\d+)\s+(\w+)\s+(\d+)\s+(.*)$/;
> > > where $waiting[lines] contains all lines not matching the string "ready and
> > > waiting".
> > >
> > > However, for the case of the response having the pattern:
> > > rpcinfo:RPC:Timed Out
> > > I would have to split this pattern with the ":" as the delimiter in order to
> > > obtain the output format as below, in the e-mail content:
> > >
> > > PROG NO VERSION PROTOCOL PORT SERVICE RESPONSE
> > > 107374        1    udp 64018
> > > rpcinfo Timed Out
> > > 100008        1    udp 55684
> > > sprayd sleeping
> > >
> > > I was wondering if there are ways which I can do so in just a single pattern
> > > matching arithmetic to obtain the attributes to correspond with the output
> > > format above?
> > >
> > > Any other better/more efficient ideas on performing such pattern match would
> > > indeed be appreciated.
> >
> > Well I can offer you the code below, which splits each line on one or
> > more whitespace characters, optionally preceded by a space. But I can't
> > see a way of describing how much of the end of the text you want as
> > the 'response'. There's nothing to differentiate taking the last word
> > of 'program 100008 version 1 sleeping' to say 'sleeping', as opposed to
> > the last two words of 'RPC: Timed out' to say 'Timed out'. Can you specify
> > what you need a little more precisely, and show us a better example of the
> > input?
> >
> >
> >   while (<DATA>) {
> >     chomp;
> >     next if /ready and waiting/;
> >     my @details = split /:?\s+/, $_, 7;
> >     shift @details;
> >     $" = ' / ';
> >     print "@details\n";
> >   }
> >
> >
> >   __DATA__
> >   100008    1   udp  55734   walld         program 100008 version 1 ready
> > and waiting
> >   107374    1   udp  64018   rpcinfo: RPC: Timed out
> >   100008    1   tcp  55684   sprayd       program 100008 version 1 sleeping
> >
> > OUTPUT
> >
> >   107374 / 1 / udp / 64018 / rpcinfo / RPC: Timed out
> >   100008 / 1 / tcp / 55684 / sprayd / program 100008 version 1 sleeping
>
> From the output generated below, I would like to obtain the string from
> "RPC: Timed out" onwards. This string corresponds to the response attribute.
> Another example of the response attribute is the "program 100008 version 1
> sleeping".
> 107374 / 1 / udp / 64018 / rpcinfo / RPC: Timed out
> 100008 / 1 / tcp / 55684 / sprayd / program 100008 version 1 sleeping
>
> Hence I would like to know if there is a more efficient way of performing a
> pattern match which also includes delimiters like the ":" and spaces? Since
> you pointed out that "There's nothing to differentiate taking the last word
> of 'program 100008 version 1 sleeping' to say 'sleeping', as opposed to the
> last two words of 'RPC: Timed out' to say 'Timed out'.", I would just like
> to obtain the service names rpcinfo and sprayd and the response attribute
> i.e. "RPC: Timed out" (ignoring the ":" before RPC i.e. ":RPC") and
> "program 100008 version 1 sleeping".

What you want is already there if you look at my code. I've writtten
it differently from your program in that I'm using 'split' instead of
regex captures. I missed the attachment on your original post. Let's
take a look at that.

  use strict;   # always
  use warnings; # usually

(or people won't be in a hurry to answer your questions!)

>   use Cwd;
>   $currDir=cwd;
>
>   $file=$currDir."/rpc.txt";

If you're always opening a file in the current directory you don't
need the 'Cwd' module. Just

  my $file = 'rpc.txt';

will do.

>   `/etc/rpcping |grep -v RPC|grep -v program >$file`;
>   print "\$file = $file \n";
>
>   @waiting = `grep -v "ready and waiting" $file`;

It's not a good idea to shell out to Unix utilities to do something
that Perl can do easily. But since this command line looks wrong to
me anyway I'm leaving it as it is. (I think it runs 'rpcping' and
writes to $file the lines which contain neither 'RPC' nor 'program'.
But that's not consistent with the file contents that you posted.)

>
>   print "Processing invalid process now ...\n";
>
>   open (MAIL, "|/usr/bin/mailx -s 'RPCPING OUTPUT' cleaw");

Again, using an external utility isn't the way to build and send
email in Perl.

>   print MAIL "PROG NO\t\t\VER\t\t\PROTO\t\t\PORT\t\t\RESPONSE\t\t\t\n";
>   for ($lines=0;$lines<@waiting; $lines++) {
>     print "\$waiting[$lines]= $waiting[$lines]\n";

This is C code written in Perl. I don't believe you're interested
in the array index - you just want to process all of the array elements,
so it should be written:

  foreach my $waiting ( @waiting ) {
    print "\$waiting = $waiting\n";

>     $waiting[$lines]=~m/^(\d+)\s+(\d+)\s+(\w+)\s+(\d+)\s+(.*)$/;

Here, instead of the regex, I would use the 'split' command that I posted
before (slightly changed here, to handle leading spaces properly).

  my @details = split /:?\s+/, $_, 6;
  shift @details unless $details[0];

now the array has the fields you wanted like this:

  prog no =   $details[0]
  version =   $details[1]
  protocol=   $details[2]
  port =      $details[3]
  service =   $details[4]
  response =  $details[5]

so you can use $details[0] through $details[5] instead of
$1 through $6.

>     print "prog no = $1\n";
>     print "version = $2\n";
>     print "protocol=$3\n";
>     print "port =$4\n";
>     print "response = $5\n";
>
>     print "$response \n";
>     print MAIL"$1\t\t$2\t\t$3\t\t$4\t\t$5\t\t\t\n";
>   }
>
>   close (MAIL);

The rest should be much the same. Try this and come back if you
need any more help.

Cheers,

Rob




-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to