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

hi,
when i ran this script its throwing me an weird error. this works perfect when i run locally, but when i ran on the server it gives me:
Use of uninitialized value in substitution (s///) at sn8.pl line 51. Use of uninitialized value in string gt at sn8.pl line 52. -1


#!/usr/bin/perl # use strict; use warnings; use List::Util q{first}; sub search_phrase{ my @array; my ( $inFile, @phrases ) = @_; my $lastPhrase = $phrases[ -1 ]; open my $inFH, q{<}, $inFile or die qq{open: $inFile: $!\n}; my @lines = <$inFH>; close $inFH or die qq{close: $!\n}; foreach my $phrase ( @phrases ) { my $rxPhrase = qr{\Q$phrase\E}; my $lineNo = first { $lines[ $_ ] =~ $rxPhrase } 0 .. $#lines; unless ( defined $lineNo ) { #print "-1"; # print qq{$phrase: not found in sequence\n}; next; } print "" if ($lines[ $lineNo ] =~ m{\Q$lastPhrase\E\s*(\d*)}); push (@array,$1); $lineNo ++; splice @lines, 0, $lineNo; } return (@array); } my $file_n = "test2.txt"; my $phrase1 = "total rejected rows:"; my $phrase2 = "total rejected recors:"; my $phrase3 = "rejectb:"; my $phrase4 = "total rejected rows:"; my @newarray=search_phrase($file_n, $phrase1, $phrase2, $phrase3, $phr +ase4); my $count=($#newarray); $newarray[$count]=~ s/\s+//g; if ((($#newarray+1)>=1) && ($newarray[$count]gt 0)) { print "$newarray[$count]\n"; } else { print "-1\n"; }

my test file is: test2.txt

This file is to check the number of occurences of the word reject total rows rejected: 80 this file just contains the phrase reject. reject:3 reject 3 reject 4 total rejected rows: 100 total rejected rows: 90 total rejected rows: 60 total rejected rows:40 total rejected rows:40 90 rows rejected for sub 999 rows rejected for sub 100 rows rejected for sub Reject_Ao total rejected recors: 60 total rejected rows:49 reject:1 390 rows rejected for sub

could somebody help me with this?
thanks,

Mercury.

Replies are listed 'Best First'.
Re: uninitialized value error
by talexb (Chancellor) on Jan 30, 2008 at 18:19 UTC

    First, let's make your code readable by running it through perltidy:

    #!/usr/bin/perl # use strict; use warnings; use List::Util q{first}; sub search_phrase { my @array; my ($inFile, @phrases) = @_; my $lastPhrase = $phrases[-1]; open my $inFH, q{<}, $inFile or die qq{open: $inFile: $!\n}; my @lines = <$inFH>; close $inFH or die qq{close: $!\n}; foreach my $phrase (@phrases) { my $rxPhrase = qr{\Q$phrase\E}; my $lineNo = first {$lines[$_] =~ $rxPhrase} 0 .. $#lines; unless (defined $lineNo) { #print "-1"; # print qq{$phrase: not found in sequence\n}; next; } print "" if ($lines[$lineNo] =~ m{\Q$lastPhrase\E\s*(\d*)}); push (@array, $1); $lineNo++; splice @lines, 0, $lineNo; } return (@array); } my $file_n = "665172.data"; my $phrase1 = "total rejected rows:"; my $phrase2 = "total rejected recors:"; my $phrase3 = "rejectb:"; my $phrase4 = "total rejected rows:"; my @newarray = search_phrase( $file_n, $phrase1, $phrase2, $phrase3, $phrase4 ); my $count = ($#newarray); $newarray[$count] =~ s/\s+//g; if ((($#newarray + 1) >= 1) && ($newarray[$count] gt 0)) { print "$newarray[$count]\n"; } else { print "-1\n"; }

    Next, when I try running your code, it works fine, and you say it works fine for you, except when you ru it on a server.

    So the obvious question (but one that I'll ask anyway) is, "What's the difference from your workstation and the server?" You're only using List::Util -- I imagine it's installed on the server, and the same version number. Is the data file the same?

    Now onto the fun part: picking out stylistic miscues.

    • You're reading the entire file into an array. it's more Perl-ish to loop around the diamond operator: (updated: please see footnote.)
      foreach my $thisLine (<$inFH>) { .. do something with $thisLine .. }
      while (<$inFH>) { .. do something with $thisLine .. }
    • You're using a variable for the filehandle -- this isn't really necessary. I suggest using something like INPUT instead.
    • You don't have the main-line enclosed in a set of braces. I like to do that, if only to remind the reader that it's the place where the action is taking place -- as opposed to some location where we're defining variables.
    • You're not describing what you're doing. Without spending a lot of time analyzing your code, it seems you're looking for key phrases in a file and grabbing the numerical value.
    • Whenever I see $phrase1, $phrase2, $phrase3 and so on, I immediately wonder, "Why isn't this program using an array?"

    Those are my thoughts. What do you think?

    Update: As both Narveson and wfsp have pointed out, for reads the entire file in, so doesn't achieve the goal I was reaching. Instead, use while. Oops.

    Alex / talexb / Toronto

    "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

      Now onto the fun part: picking out stylistic miscues.

      • open INPUT is traditional, it's true, but open my $inFH is far better. The traditional INPUT is global, my $inFH is lexical. For the drawbacks of global variables and the advantages of lexicals, see e.g. Conway, Perl Best Practices.
      • Processing a file one line at a time is of course a good idea. The way to do it (and this is traditional) is while (my $thisLine =<$inFH>)
Re: uninitialized value error
by GrandFather (Saint) on Jan 31, 2008 at 00:03 UTC

    You push $1 onto @array (push (@array, $1);) regardless of getting a match in the previous regex. Unless the last matching line in your file is a well formed $lastPhrase line, your code as it stands will fail as you have noted.

    The following test code illustrates the problem:

    use strict; use warnings; use List::Util qw{first}; my $file = <<FILE; total rejected recors: 10 FILE my @phrases = ( "total rejected rows:", "total rejected recors:", "rejectb:", "total rejected rows:" ); open my $inFile, '<', \$file; my @newarray = search_phrase ($inFile, @phrases); close $inFile or die qq{close: $!\n}; $newarray[$#newarray] =~ s/\s+//g; if (@newarray && $newarray[$#newarray] > 0) { print "$newarray[$#newarray]\n"; } else { print "-1\n"; } sub search_phrase { my ($inFile, @phrases) = @_; my @array; my $lastPhrase = $phrases[-1]; my @lines = <$inFile>; foreach my $phrase (@phrases) { # Find the first match in the remaining lines for the current +phrase my $lineNo = first { $lines[$_] =~ /\Q$phrase\E/ } 0 .. $#line +s; next unless defined $lineNo; # No line containing current phra +se print "Found: $lines[$lineNo]" if ($lines[$lineNo] =~ m{\Q$lastPhrase\E\s*(\d+)}); push (@array, $1); $lineNo++; splice @lines, 0, $lineNo; # Delete processed lines } return @array; }

    Perl is environmentally friendly - it saves trees
      Hi all,
      Thanks for all ur responses
      First I would like to explain what is this script all about.
      The arguments passed are file_name and Search phrases (for eg: reject:, total rejected recors:, total rejected rows:, and so on...)

      The number of arguments passed may vary... But the first argument is always the file_name.

      first it will check for phrase 1 and then from that line number phrase 2 and then phrase 3 and return phrase 3 value .

      that is why the order in which we search is very important...

      lets say we have 4 arguments including file name...

      if (phrase 1 exists) ---------- if (phrase 1 doesnt exists)

      from that line number ----------- search for phrase 2

      search for phrase 2 ---------- if (phrase 2 also doesnt exists)
      from that line number ---------- search for phrase 2 and return phrase 3

      even if last phrase was present before, we shud ignore it and follow the order in which the phrases are passed as arguments.... and return the last phrase's value (ie., 45)


      if the last phrase was not found in that file then it should print -1 and exit


      if the last phrase is given twice, it shud return the last found value in that given order.

      and one more last thing, this script works only for returning the value which is at the end of the line..
      but doesnt return the value which is at the beginning of the line.
      for eg:
      total rejected rows: 90
      it returns 90 or whatever value it is
      but not
      50 rows rejected
      that it doesnt return 50
      thanks,
      Mercury.