Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Is there a Better work around rather than 9 If else Looping

by msk_0984 (Friar)
on May 23, 2007 at 12:16 UTC ( [id://616986]=perlquestion: print w/replies, xml ) Need Help??

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

Respected Monks,

Firstly, thanks for the prevous reply which i hav got for my recent post through which i was really able to learn new things. At Perl Monks site its really some thing like evolving day by day.

As over to the main topic, i am creating a script for auditing multiple log files. These log files contain data in the following format .....

[Tue May 22 14:47:44 IST 2007][192.168.1.91][sunny][Distribution] Err +or: ct_connect(): directory service layer: internal directory control + layer error: Requested server name not found. <p> [Tue May 22 14:47:44 IST 2007][192.168.1.81][sridhar][PAD Manager] Wa +rning: Failback not supported. <p> [Tue May 22 14:47:44 IST 2007][192.168.1.93][sentini][Remote Editing] + Error: Results processing failed. <p>
I have the scenarios to audit this logs say : Need to get data from logs w.r.t Eg1: user -> sunny Host -> 192.168.1.93 module -> Remote Editing Eg2: user -> sunny Host -> All ( means from all hosts) module -> Remote Editing Similarly we have all the 8 secanrios for which i have written a script using if - else looping
#! /usr/bin/perl my $sel_user,$sel_host,$sel_mod; print "\nEnter your choice for user: "; $sel_user=<STDIN>; chomp($sel_user); print "\nEnter your choice for host: "; $sel_host=<STDIN>; chomp($sel_host); print "\nEnter your choice for module: "; $sel_mod=<STDIN>; chomp($sel_mod); my $dir = './logs/commonlogs'; opendir my $dh, $dir or die "Can't opendir '$dir': $!\n"; my @files = grep { ! -d "$dir/$_" and ! /user.log/ } readdir $dh; foreach my $fname ( @files ) { #chomp($fname); $filename="$dir/$fname"; open(FH, $filename) or die "Error : $! \n" ; while($audit_data=<FH>) ### For greping out required data ####### +####################### { @check=split(']\[|]\s+|^\[',$audit_data); #print " $_ :: \n \n audit data $audit_data \n \n" foreach +(@check); if($check[3] =~ /^$sel_user$/ && $check[2] =~ /^$sel_host$ +/ && $check[4] =~ /^$sel_mod$/) { print " In first -- >> $audit_data"; } elsif($check[3] =~ /$sel_user/ && $check[2] =~ /$sel_host/ + && $sel_mod =~ /All/i) { print "In Second --- >> $audit_data"; } elsif($check[2] =~ /$sel_host/ && $check[4] =~ /$sel_mod/ +&& $sel_user=~ /All/i) { print "In Third -- >$audit_data"; } elsif($check[3] =~ /$sel_user/ && $check[4] =~ /$sel_mod/ +&& $sel_host=~ /All/i) { print "In Forth --> $audit_data"; } elsif($sel_user =~ /All/i && $sel_mod =~ /All/i && $check[ +2] =~ /$sel_host/) { print " In fifth -> $audit_data"; } elsif($sel_user =~ /All/i && $check[4] =~ /$sel_mod/ && $s +el_host =~ /All/i) { print " In sixth -> $audit_data"; } elsif($check[3] =~ /$sel_user/i && $sel_mod =~ /All/i && $ +sel_host =~ /All/i) { print " In seventh -> $audit_data"; } elsif($sel_user =~ /All/i && $sel_mod =~ /All/i && $sel_ho +st =~ /All/i) { print " In last -> $audit_data"; } } }
This was working fine and i was able to get all the 8 scenarios which i was looking out for, but i felt it is not effective since i had to right 8 loops for this, i just want to know that rather than using 8 If -else looping any better effecient and effective way to do it.

Work Hard Party Harderrr!!
Sushil Kumar

Replies are listed 'Best First'.
Re: Is there a Better work around rather than 9 If else Looping
by NetWallah (Canon) on May 23, 2007 at 13:36 UTC
    Sushil - your code would be easier to read, maintain, expand and debug, if you used perl HASHES.

    Hashes would also solve your multi-if logic.

    Here is a structure outline to get you started:

    my (%user_choice, %audit_rec); # Update: Parens added to fix syntax # Get User input into $user_choice{user}, $user_choice{module} .. and +$user_choice{host} #after reading the record, get it into %audit_rec like this: @audit_rec{ qw| time host user module msg | } = # This is a "Hash-sl +ice" split(']\[|]\s+|^\[',$audit_data); # Now, you can compare $user_choice{xxx} with $audit_rec{xxx} , and l +oop through values for xxx. # A more advanced technique would be to create a "dispatch table" hash + # Search for that on this site, if interested.
    update:minor syntax update, to fix issue described by jdporter, below.

         "An undefined problem has an infinite number of solutions." - Robert A. Humphrey         "If you're not part of the solution, you're part of the precipitate." - Henry J. Tillman

      Err...

      my %user_choice, %audit_rec;
      gives the warning
      Parentheses missing around "my" list at...
      and the error
      Global symbol "%audit_rec" requires explicit package name at...
      at least for those of us who use strict and warnings.

      A word spoken in Mind will reach its own level, in the objective world, by its own weight
Re: Is there a Better work around rather than 9 If else Looping
by blazar (Canon) on May 23, 2007 at 13:37 UTC
    This was working fine and i was able to get all the 8 scenarios which i was looking out for, but i felt it is not effective since i had to right 8 loops for this, i just want to know that rather than using 8 If -else looping any better effecient and effective way to do it.

    Indeed in Perl there's hardly ever the need to have long sequences of if's, elsif's, etc. But it's not as much a matter of efficiency and effectiveness as much as of clumsiness: your code is hard to follow at all. So what can you do instead? One common way is a dispatch table (look it up in Super Search): that approach is very easy when you have to take an action based on which one of a given set of strings a particular one is. In this case you're having a slightly more complex situation, but at a first glance it seems to me that you can still build unique keys for a hash to use. At a further reading, I notice that all your actions amount to some print's, so the hash needs not even be one of coderefs: it's enough that values are strings. That should make for more compact and more readable code.

Re: Is there a Better work around rather than 9 If else Looping
by GrandFather (Saint) on May 23, 2007 at 21:34 UTC

    Using a bit for each test and a dispatch table may help:

    use warnings; use strict; my $tName = 'Fred'; my $tHost = 'All'; my $tModule = 'Bobble'; my %dispatch = ( 0 => \&NoMatch, 1 => \&Name, 2 => \&Host, 3 => \&NameHost, 4 => \&Mod, 5 => \&NameMod, 6 => \&HostMod, 7 => \&NameHostMod, ); while (<DATA>) { chomp; my ($name, $host, $mod) = split; my $code = $name eq $tName || $tName eq 'All' ? 1 : 0; $code |= $host eq $tHost || $tHost eq 'All' ? 2 : 0; $code |= $mod eq $tModule || $tModule eq 'All' ? 4 : 0; $dispatch{$code}->($_); } sub NoMatch { print "NoMatch\n"; } sub Name { print "Name\n"; } sub Host { print "Host\n"; } sub NameHost { print "NameHost\n"; } sub Mod { print "Mod\n"; } sub NameMod { print "NameMod\n"; } sub HostMod { print "HostMod\n"; } sub NameHostMod { print "NameHostMod\n"; } __DATA__ Fred Wizzle Tangle Fred Plonk Bobble Joe Wizzle Bobble Bob Fizz Knot

    Prints:

    NameHost NameHostMod HostMod Host

    DWIM is Perl's answer to Gödel
Re: Is there a Better work around rather than 9 If else Looping
by Util (Priest) on May 23, 2007 at 22:21 UTC

    Working, (loosely) tested code:

    #!/usr/bin/perl use strict; use warnings; sub grep_dir_of_logs { die unless @_ == 4; my ( $dir, $sel_user, $sel_host, $sel_mod ) = @_; $_ = lc $_ for $sel_user, $sel_host, $sel_mod; my $inside_brackets_re = qr{ \[ ( [^[]+ ) \] }msx; my $line_re = qr{ \A $inside_brackets_re $inside_brackets_re $inside_brackets_re $inside_brackets_re \s* (\S.*?) \s* \z }msx; opendir my $dh, $dir or die "Can't opendir '$dir': $!\n"; my @files = grep { !/user.log/ } readdir $dh; closedir $dh; foreach my $fname ( @files ) { my $filename = "$dir/$fname"; next if -d $filename; open my $fh, $filename or die "Error opening '$filename': $!"; while (<$fh>) { chomp; my ( $date_string, $host, $user, $module, $message ) = /$line_re/ or die; next if $sel_user ne 'all' and $sel_user ne lc $user; next if $sel_host ne 'all' and $sel_host ne lc $host; next if $sel_mod ne 'all' and $sel_mod ne lc $module; print "Passed: $_\n"; } close $fh or warn "Error closing '$filename': $!"; } return; } use IO::Prompt; grep_dir_of_logs( './logs/commonlogs', prompt('User : '), prompt('Host : '), prompt('Module: '), );

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://616986]
Approved by grep
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (2)
As of 2024-04-20 05:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found