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

I humbly ask for help on the following matter:

I have a little piece of code, that isn't working properly. It's supposed to take all files from a directory "mail" and print the first line from each of them. But as I run it, it displays the following warning: "use of uninitialized value in print...etc", and, obviously, doesn't print anything. I know, the solution must be simple, but I just can't find it. Thank you in advance, and here's the code:

#/usr/bin/perl use strict; use warnings; opendir (DIR, "\mail"); foreach my $file (readdir DIR){ open WRITE, '<', '$file'; my $text = <WRITE>; print $text; }

Replies are listed 'Best First'.
Re: Read first line from each file in a directory
by davido (Cardinal) on Dec 16, 2011 at 16:57 UTC

    Let's summarize the problems:

    • You're not checking the return value of opendir, so you don't know if it succeeded.
    • You're not checking the return value of open, so you don't know if it succeeded.
    • You should be opening the '/mail' directory, not "mail" (which is what the string looks like after the backslash is processed away).
    • You are attempting to read from '$file' (that's the literal filename $file), when you mean to be reading from the filename contained in the scalar variable $file.
    • You're calling your input filehandle WRITE, which isn't a bug but is confusing.

    Fix those things and see how it goes.

    Update: At Not_A_Number's request/suggestion I'm updating to add the very good points mentioned by MidLifeXis and toolic.

    • The file you open needs to have the path prepended to it.
    • readdir returns the '.' and '..' directories too. A -f test would determine that you're looking at a file, not another directory.
    • autodie would eliminate the need to explicitly check the return values of your IO operations.

    That gives you a total of eight "bullet points" to work on. Once they're resolved, assuming some other problem hasn't been introduced in the process, you'll be on track.


    Dave

Re: Read first line from each file in a directory
by choroba (Cardinal) on Dec 16, 2011 at 16:26 UTC
    You should check the output of open:
    open WRITE, '<', '$file' or die $!;
    You are trying to open the file named '$file', quotes included. No such files exists. You need no quotes here.
Re: Read first line from each file in a directory
by MidLifeXis (Monsignor) on Dec 16, 2011 at 16:43 UTC

    • As others have mentioned, '$file' should be $file (no quotes), and check the return code of your opendir and open calls.
    • You also have probably chosen a bad name for your file handle. WRITE for a read-only file handle would cause at least a double take.
    • I believe that you will find that $file contains the name of the file without the directory name. You probably mean to use "$dir/$file" (for appropriate values of $dir).

    --MidLifeXis

Re: Read first line from each file in a directory
by Tux (Canon) on Dec 16, 2011 at 16:25 UTC

    Backslash characters are not what you think they are in double-quoted strings. You probably just want to open using Unix/Linux style, which is recognized by windows, or you should use File::Spec.

    open DIR, "/mail";

    or maybe even use glob (). I have no idea how well that works on Windows

    foreach my $f (glob ("/mail/*.*")) { open my $fh, "<", $f; print scalar <$fh>; }

    Enjoy, Have FUN! H.Merijn
Re: Read first line from each file in a directory
by toolic (Bishop) on Dec 16, 2011 at 17:32 UTC
    Another problem you may have is that readdir returns sub-directories as well as files. If you are on unix, that means you will get the special . and .. directories, which you do not want. You will need grep and -f.

    See also autodie

Re: Read first line from each file in a directory
by mr.nick (Chaplain) on Dec 16, 2011 at 16:24 UTC
    Try testing if your opendir and open succeeded.

    mr.nick ...

      Already did, they work.

        I doubt that. As choroba stated, you are actually trying to open a file named $file.

        mr.nick ...

        And your opendir will only work (by accident) if you are in the root folder when you start the script.


        Enjoy, Have FUN! H.Merijn
Re: Read first line from each file in a directory
by TJPride (Pilgrim) on Dec 16, 2011 at 16:44 UTC
    Maybe something like this:
    #\usr\bin\perl use strict; use warnings; opendir (DIR, '\mail') || die "Can't open \mail.\n"; for my $file (readdir DIR) { if (!open (WRITE, "\mail\$file")) { print "Can't open \mail\$file\n"; next; } my $text = <WRITE>; print $text; }