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

I have to open all the files in a directory, the name of which will be given in the command line arguement .My code is

; #!usr/bin/perl -w use strict; use warnings; my $handle=$ARGV[0]; opendir(D,$handle) or die "cannot open"; my @files=readdir(D); foreach my $file(@files) {open (MYFILE,"$file") or die"oops"; } closedir(D)

The directory in command line has 5 files. It gives output as oops .I am a noob to perl so it will be helpful if you provide a basic explanation and the code i need to use . thanks

Replies are listed 'Best First'.
Re: cant open files from a directory
by parv (Parson) on Jan 31, 2014 at 06:39 UTC

    Include the reason of error by use of $! variable ...

    open ... or die "Death is here because: $!.";

    Mind that readdir gives a file name below the directory being read from (relative path). You may need to supply the parent directory as appropriate to form correct path of file to be (found &) opened.

Re: cant open files from a directory
by vinoth.ree (Monsignor) on Jan 31, 2014 at 07:20 UTC
    parv++

    readdir(D) gives only the file names, if you included the $! in the file open function it could have given you the "oops No such file or directory" error message, in the file open function give the absolute path to open the file.

    Here is the code I checked.

    my $handle=$ARGV[0]; opendir(D,$handle) or die "cannot open $!"; my @files=readdir(D); print "@files\n"; foreach my $file(@files) { open (MYFILE,"$handle/$file") or die "oops $!"; while(<MYFILE>) { print $_; } } closedir(D);


    All is well

      readdir gives not only the file names but also the directory names present inside your $handle.

      open (IN, "$handle/$file") on a directory will give you an error of course ;-)

      you will have to test $file for being a file before opening it.

        A directory is also a file.

Re: cant open files from a directory
by parv (Parson) on Jan 31, 2014 at 08:24 UTC
Re: cant open files from a directory
by kcott (Archbishop) on Feb 01, 2014 at 04:53 UTC

    G'day garny,

    Welcome to the monastery.

    The following repeats some of the information you've already been given. I've expanded on most of this because you say "I am a noob to perl" and you might as well get into good habits from the outset.

    'die "cannot open"' and 'die"oops"' are poor error messages that convey little information. I find the autodie pragma is the easiest option; however, if you wish to hand-craft your error messages, do so in a useful fashion (e.g. 'die "Can't open $file for reading: $!"').

    Unless you have a good reason not to, use lexical filehandles and directoryhandles (see examples in open and readdir respectively). Package variables (e.g. D and MYFILE in your posted code) are slower to access than lexical variables and you can't control their scope the way you can with lexical variables: in a tiny script, such as you have here, those reasons probably won't matter much, if at all; when you start writing more complex code, you may find this will save you debugging headaches (a good reason to avoid package variables even if the speed factor is negligible).

    Get into the habit of using the 3-argument form of open: the documentation has details.

    Close handles when you've finished with them; don't leave this until the end of your script. In the code your posted, the closedir() statement could have been placed immedaitely after the readdir() statement.

    As explained in the readdir documentation, this function returns directory entries. While this will include the types of files you're intending to read (source code, config files, etc.), it will also include directories (at least the current, '.', and parent '..', directories) as well as symbolic links, character and block special files and so on: you can use the file test operators to filter the type(s) you want.

    Instead of using

    my @files = readdir($dirhandle);

    which returns just the names of all the files, directories, etc., you can use

    my @files = grep { -f } map { "$dir/$_" } readdir($dirhandle);

    which returns the pathnames of just the files you want.

    [Also consider File::Spec for a more portable solution for "$dir/$_".]

    -- Ken

      my @files = grep { -f } map { "$dir/$_" } readdir($dirhandle);

      To combat the excessive grepping & mapping going on above ...

      my @files = map { -f $_ ?"$dir/$_" : () } readdir( $dirhandle ) ;

        I'd hardly consider one grep and one map to be "excessive grepping & mapping" nor something that one would need to "combat".

        However, should you prefer the style you've posted, "-f $_" suffers from the problem already pointed out four times in this thread.

        You could employ excessive usage of "$dir/$_", though. :-)

        -- Ken

Re: cant open files from a directory (Path::Tiny)
by Anonymous Monk on Jan 31, 2014 at 08:15 UTC

    readdir is the devil, use Path::Tiny, it throws "exceptions" like autodie

    use Path::Tiny qw/ path /; my @files = path( $dirpath )->realpath->children(); for my $file( @files ){ my $fh = path( $file )->openr_raw; while( <$fh> ){ ... } }