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

Monks,
I am working on a task to parse the logfiles which are in side the latest directories.
Bellow is the code i have written to open the latest logfile,for this i predeclared the path to get the directory list.
#!/usr/bin/perl $arg=$ARGV[0]; $pattern="build.log"; $path="/remote/scm/rsync/builds/$arg/FailedInformal"; #print "$path\n"; @releases=`ls -1 $path`; #print "@releases\n"; $x=0; foreach $file(@releases) { if($file=~/^\d/) { $dlist[$x]=$file; } $x++; } #print "@dlist\n"; @three=@dlist[-1,-2,-3]; #print "@three\n"; $latest=$three[0]; print "$latest\n"; $path1="$path/$latest"; print "$path1\n"; @logs=`ls $path1`; #print "@logs\n"; #print "$logs[1]\n"; #print "$path1/@logs[1]"; $p= open(F,"$path1/build.log")or die "$!\n"; while(<F>) { chomp; print "$_\n"; }
3.0.0.0.118 3.0.0.0.113 3.0.0.0.111 3.0.0.0.118 /remote/scm/rsync/builds/v_dialer/FailedInformal/3.0.0.0.118 No such file or directory

Replies are listed 'Best First'.
Re: problem to open a specified path file in open system call
by tirwhan (Abbot) on Jul 14, 2007 at 12:43 UTC

    Your problem is that the "ls -1" system call returns your directory names with a newline character ("\n") appended and you're not removing that character before attempting to open the file. Add a chomp:

    if($file=~/^\d/) { chomp $file; $dlist[$x]=$file; }

    That being said, you should also:

    • use strict; and use warnings; at the top of your script
    • use a lexical variable for the filehandle and the three-argument form of open: open (my $fh,"<","$path1/build.log")or die "$!\n";
    • Use the perl inbuilt functions (opendir,readdir) for reading directory contents instead of ls
    • Consider using File::Find or File::Find::Rule for locating the files you want to handle

    All dogma is stupid.
Re: problem to open a specified path file in open system call
by naikonta (Curate) on Jul 14, 2007 at 12:43 UTC
    It's clear that you're working on files in a directory but I'm not sure what are you trying to achieve as you provide a very small amount of information on that. For what you're doing, Perl provides built-in functions so you don't need external program like ls: opendir, readdir, and closedir. Examples (untested),
    my $dir = shift; # get the first command line arg my $path = "/remote/scm/rsync/builds/$arg/FailedInformal"; opendir DIR, $path or die "Can't open $path: $!\n"; my @releases = grep {/^\d/} readdir DIR; # NOW, it's up to you what you want with files you find # in @releases # get the latest three my @three = @releases[-1,-2,-3]; # get only the very latest my $latest = $relreases[-1]; .... # and closing the DIR handle is good closedir DIR;
    One thing to note: since you're working on the current directory (wherever it is), you have to use the original path to work on a file. For example, the following is wrong,
    open FILE, $latest or die "Can't open $latest: $!\n"; ....
    Instead, you have to write,
    # presume / as path separator my $latest_file = "$path/$latest"; open FILE, $latest_file or die ...;
    As to the error message, it just says what the perl interpreter thinks, the file doesn't exist. Check it manually if that's not what you think.

    Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

      Hi Naikonta,
      Thx for quick reply,the actual problem is as below
      $path1="/remote/scm/rsync/builds/v_dialer/FailedInformal/3.0.0.0.118"; i can able to open the file by command prompt as
      vi /remote/scm/rsync/builds/v_dialer/FailedInformal/3.0.0.0.118/build.log
      but in open comman unable to open
      open(FILE,$path1/build.log) or die "$!\n"; why this will not open the build.log?
      whats wrong in open() call...litrally i am not getting where its going wrong...help me out to proceed further
        The problem with your usage on open is that it can't open a file with newline character in its name. As pointed out by tirwhan, the embedded newline characters in your filenames came from ls command. You need to chomp them.
        my @files = `ls -1`; chomp @files; # or in one line chomp(my @files = `ls -1`);
        Using built-in opendir and readdir would be safer for you, and no extra processes needed.

        Open source softwares? Share and enjoy. Make profit from them if you can. Yet, share and enjoy!

        open(FILE,$path1/build.log) or die "$!\n"; why this will not open the build.log?

        In case it's not just a typo in this post...  you'd need to either interpolate

        open(FILE,"$path1/build.log") or die "$!\n";

        or concatenate the strings

        open(FILE,$path1."/build.log") or die "$!\n";

        Using strictures would have revealed the problem. With use strict; you'd have gotten:

        Bareword "build" not allowed while "strict subs" in use at ./626616.pl + line 8. Execution of ./626616.pl aborted due to compilation errors.

        and with use warnings; even more:

        Unquoted string "build" may clash with future reserved word at ./62661 +6.pl line 8. Name "main::FILE" used only once: possible typo at ./626616.pl line 8. Argument "build" isn't numeric in division (/) at ./626616.pl line 8. Argument "." isn't numeric in division (/) at ./626616.pl line 8. Illegal division by zero at ./626616.pl line 8.