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

Hi expert,
I have a build log file in that I am looking for string like "2 failed" or "any number" failed .I have written a small code like this but not getting it right. Can I get some assistance.?
file = "D:/perl/02.log"; open (FILE,$file) || die ("cant open file"); $true=1; ##### look for errors while (<FILE>) { #if (/^Status : ERRORS/) if (/\d{1-9} failed/ ) { $true=0; print "There are build errors\n"; exit 0; } }
Thx av

Replies are listed 'Best First'.
Re: Find a pattern
by GrandFather (Saint) on Jan 28, 2011 at 09:25 UTC

    I strongly recommend that you use strictures (use strict; use warnings;). In this case you would have received a compile error complaining about using a 'bare word'.

    You should also use the three parameter version of open and you should use lexical file handles. I've updated your code with these changes below:

    use warnings; use strict; my $file = "D:/perl/02.log"; open my $inFile, '<', $file or die "cant open $file: $!"; # Look for errors while (<$inFile>) { if (/^Status : ERRORS|\d+ failed/) { print "There are build errors (see line $.)\n"; exit 0; } }

    Note that I also combined the commented out 'Status : ERRORS' test with the test you were using so that either string will be detected and I added the line number where the error line was found to the build errors message.

    True laziness is hard work
      Of course it depends on how you want to use this code, but personally I would change the error message to go to stderr instead of stdout, and exit with something other than zero, which by convention means success. Both can be done using die:
      print "There are build errors (see line $.)\n"; exit 0;
      into:
      die "There are build errors (see line $.)\n";
Re: Find a pattern
by fisher (Priest) on Jan 28, 2011 at 09:11 UTC
    well, first of all, the very first line in your code:
    file = "D:/perl/02.log";
    I think 'file' intended to be a variable, isn't it? If yes, it should be written as '$file'.

    Second, in the second line you use a wrong call to 'open'. First parameter to open should be a so called 'file handler', then the operation and file name:

    open (FH, "<", $file) or die "cant open file";
    third, regexp. I think you mean actually
    if (/2 failed/)
    ...according to your question. What you wrote is 'a one to nine digits, then space, then the word "failed"'.

      What you wrote is 'a one to nine digits, then space, then the word "failed"'.

      No. /\d{1-9}/ matches a digit followed by a "{" followed by a "1" followed by a "-" followed by a "9" followed by a "}".

      To match any number (for some definition of number), /\d+/ would do.

        To make this answer a little more helpful:
        The correct expression to match "a series of 1 to 9 digits" is:
        /\d{1,9}/ or /[0-9]{1,9}/ - note the comma, not dash

        1 to 9 digits between 1 and 9:
        /[1-9]{1,9}/

        Any number of digits between 1 and 9: /[1-9]+/
        Oh, thank you, my fault; I saw comma inplace of dash

      Actually the OP's open:

      open (FILE,$file) || die ("cant open file");

      is correct, but old school and frowned on. As you suggest the three parameter version of open is better, but even better is to use it with a lexical file handle. Using a lexical file handle ensures the file is closed when the file handle variable goes out of scope. The improved version of open is:

      open my $fileIn, "<", $file or die "Can't open $file: $!";

      Note too the file name mentioned in the die and the use of $! to give the system provided failure message. Both of those can help a lot when figuring out why an open failed.

      True laziness is hard work

      All,
      Thanks a lot
      My requirement is such that if the log contains the string
      like "2 failed" or "3 failed"..."<any number except 0>" failed.
      I have some other processing to do. So will the below code work.

      my $file = "D:/perl/02.log"; open my $inFile, '<', $file or die "cant open $file: $!"; # Look for errors while (<$inFile>) { if (/\d{1-9} failed/) { print "There are build errors (see line $.)\n"; exit 0; } }

      Thks AV

        It's a slightly tricky match to get right depending on just how fussy you really want to be. Using a negative look ahead helps cover most bases though. Consider:

        use strict; use warnings; my $str = <<STR; Errors: 0 failed Errors: 01 failed Errors: 1 failed Errors: 10 failed Errors: None failed Ben10 failed STR open my $fIn, '<', \$str; while (<$fIn>) { print if /\b(?!0+\b)\d{1,9} failed/; }

        Prints:

        Errors: 01 failed Errors: 1 failed Errors: 10 failed

        The (?!0+\b) is the negative look ahead that fails the match if a zero value (regardless of the number of 0 digits) is found. The \b's are there to ensure all the digits in the number are matched.

        True laziness is hard work
        Won't work. Use /[1-9] failed/ for that. \d{1-9} would actually parse a digit followed by '{1-9}' or a number with 1 to 9 digits if the '-' were a ','. More info in perlre.