ajay.awachar has asked for the wisdom of the Perl Monks concerning the following question:

Hi All, I am trying to read a file to count the occurrence of CRITICAL and MAJOR errors in a big log file but it is giving me following error "readline() on closed filehandle FILE" Following is the code
#!/bin/perl -w # Changing dir to Log dir `cd /opt/app1/osa/ebcp/5_5_4/log/`; open(FILE,'AppOsaEbcp1.log'); $major=0; $minor=0; $critical=0; while(<FILE>) { chomp; if(/MAJOR/) { $major=$major+1; } if(/CRITICAL/) { $critical=$critical+1; } if(/MINOR/) { $minor=$minor+1; } } close(FILE); printf("Count of MAJOR = $major, CRITICAL = $critical, MINOR = $minor +\n");
Can anyone explain me the problem with above script and suggest a solution for it. Thanks and Regards, Ajay

Replies are listed 'Best First'.
Re: FILE reading question.(closed filehandle) issue in script
by linuxer (Curate) on Apr 05, 2009 at 16:54 UTC

    Hi,

    why don't you use Perl's own chdir?

    How do you know, that the open() was successful. You should always check for success...

    Perl provides its own chdir function. There is no need to use backticks and system commands for this.

    Every open() (and other calls) should be checked for success, otherwise you don't know wether it worked or not...

    #!/bin/perl -w use strict; ## be strict! always! my $logdir = '/opt/app1/osa/ebcp/5_5_4/log'; my $logfile = 'AppOsaEbcp1.log'; # Changing dir to Log dir; use perl! chdir $logdir or die "chdir $logfile failed: $!\n"; # check open for success!! open my $fh, '<', $logfile or die "$logfile: open failed: $!\n"; my $major=0; my $minor=0; my $critical=0; while( <$fh> ) { chomp; if ( /MAJOR/ ) { $major++; } elsif ( /CRITICAL/ ) { $critical++; } elsif ( /MINOR/ ) { $minor++; } } close $fh or die "$logfile: close failed: $!\n"; # no need for printf if you want to print simple strings print "Count of MAJOR = $major, CRITICAL = $critical, MINOR = $minor\n +";

    Update

    a shorter version:

    #!/bin/perl -w use strict; ## be strict! always! my $logdir = '/opt/app1/osa/ebcp/5_5_4/log'; my $logfile = 'AppOsaEbcp1.log'; # Changing dir to Log dir; use perl! chdir $logdir or die "chdir $logfile failed: $!\n"; # check open for success!! open my $fh, '<', $logfile or die "$logfile: open failed: $!\n"; my %count; while( <$fh> ) { if ( /(MAJOR|MINOR|CRITICAL)/ ) { $count{$1}++; } } close $fh or die "$logfile: close failed: $!\n"; # now with a printf() printf( "Count of MAJOR = %d, CRITICAL = %d, MINOR = $%d\n", @count{qw(MAJOR CRITICAL MINOR)} );

    Both code examples are untested!

    update: fixed variable mismatch ($line vs. $_)

      ...could be even shorter - use autodie; would remove the requirement for the ... or die ...; statements in 3 places :D

      A user level that continues to overstate my experience :-))
      Hi

      Thanks for your valuable suggestion.

      It worked perfectly fine for above stated problem.

      Thanks,

      Ajay
Re: FILE reading question.(closed filehandle) issue in script
by apl (Monsignor) on Apr 05, 2009 at 16:55 UTC
    Try replacing
    `cd /opt/app1/osa/ebcp/5_5_4/log/`; open(FILE,'AppOsaEbcp1.log');
    with
    use strict; use warnings; open(FILE,'/opt/app1/osa/ebcp/5_5_4/log/AppOsaEbcp1.log') or die "open + failed: $!\n";
      Hi,

      Thanks for your valuable suggestion. It worked
      perfectly fine.


      Thanks,

      Ajay
Re: FILE reading question.(closed filehandle) issue in script
by morgon (Priest) on Apr 05, 2009 at 19:51 UTC
    You are really, really lucky that your script just dies (and is not silently corrupting something).

    Before I explain what is happening I reiterate the things you should ALWAYS do (linuxer above already shows how to do it).

    - use strict
    - use warnings
    - don't use backticks when you don't need the output
    - don't use barewords as filehandles but lexical variables
    - ALWAYS check the result of sys-calls

    So what is happening in your script?

    Contrary to what you might believe the `cd log-dir` does not change the working directory of the perl-script. Instead it forks off a shell which cds into that direcory, but it is only this shell that changes the direcory. After the backtick returns your script is still in the same dir. So the open fails because your are in the wrong dir. And now you are lucky because you try to read from an invalid file-handle which aborts the script. Imagine you had another file in your script's working dir named 'AppOsaEbcp1.log' - your script would use that rather then the one in the log-dir and you would not even notice it ...