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

Howdy all...it's me and my next beginner's problem. So far I have written the following code. It's pretty obvious what it does (at the moment anyway). What I'm having troubles with is getting the directories to print out before the files. The order in which they appear in my while loop doesn't seem to matter which seems kinda weird to me.

Eventually all of it will need to get printed out to a file, but I'll cross that bridge soon (who knows...how I've written this script so far may have pre-burnt that bridge? lemme know please). Also, I'm trying to do this one without using the DirHandle module.
#!usr/bin/perl use warnings; use strict; my $dir = "/Users/ctp/perlwork"; opendir (DIRHANDLE, $dir) or die "can't open $dir: $!"; print "<HTML>\n<HEAD></HEAD>\n<BODY>\n"; while ( defined (my $file = readdir DIRHANDLE)) { next if $file =~ /^\.\.?$/; print "<B>$file</B><BR>\n" if -d "$dir/$file"; print "$file<BR>\n" if -T "$dir/$file"; } closedir (DIRHANDLE); print "</BODY>\n</HTML>\n";
As always - many thanks in advance!

ps - I'm using strict all the time now...see, I told you I'd get there ;-)

Replies are listed 'Best First'.
Re: reading files and directories
by Hena (Friar) on Jan 07, 2004 at 09:13 UTC
    The while loop works on order what the DIRHANDLE gives out. This ofcourse isn't sorted on the dir basis. I modified it a bit to do the sorting.
    #!/usr/bin/perl use warnings; use strict; my $dir = "/Users/ctp/perlwork"; # read all entries from dir and skip '.' and '..' directories opendir (DIRHANDLE, $dir) or die "can't open $dir: $!"; my @list=grep !/^\.\.?\z/, readdir DIRHANDLE; print "<HTML>\n<HEAD></HEAD>\n<BODY>\n"; # now we sort the list on directory basis foreach my $file (sort {-d "$dir/$b" <=> -d "$dir/$a"} @list) { print "<B>$file</B><BR>\n" if -d "$dir/$file"; print "$file<BR>\n" if -T "$dir/$file"; } closedir (DIRHANDLE); print "</BODY>\n</HTML>\n";
    Few extra pointers. Order of $b and $a defines whether dirs or files come first. You also could use -T in there. And use of @array before could be removed. Update: put your dir instead of mine :P.
Re: reading files and directories
by grinder (Bishop) on Jan 07, 2004 at 09:59 UTC
    next if $file =~ /^\.\.?$/;

    When dealing with readdir, a better habit to get into for dealing with the . (current) and .. (parent) entries is to name them explicitly:

    next if $file eq '.' or $file eq '..';

    There's only two of them, no need to haul in regexp machinery just for that. If you want to be really platform agnostic, you could use File::Spec and

    use File::Spec qw/curdir updir/; next if $file eq curdir() or $file eq updir();

    Addendum: see this note which summarises the issue.

      Remember that File::Spec is OO (only class methods, but OO nonetheless).

      You need either:

      use File::Spec; next if $file eq File::Spec::->curdir() or $file eq File::Spec::->updi +r();
      or to use the non-OO File::Spec::Functions:
      use File::Spec::Functions qw/curdir updir/; next if $file eq curdir() or $file eq updir();
Re: reading files and directories
by DrHyde (Prior) on Jan 07, 2004 at 09:53 UTC
    Try replacing your while loop with something like this (untested):
    my @dircontents = readdir(DIRHANDLE); my @dirs = grep { -d $_ && $_ !~ /^\.\.?$/ } @dircontents; my @files = grep { -f $_ } @dircontents; print "<B>$_</B><BR>\n" foreach (@dirs); print "$_<BR>\n" foreach (@files);
    That can, of course, be golfed down quite a bit but hopefully it's pretty clear what's going on.
Re: reading files and directories
by Anonymous Monk on Jan 07, 2004 at 09:01 UTC
    The order in which they appear in my while loop doesn't seem to matter which seems kinda weird to me.
    How do you figure? The order matters.
    Eventually all of it will need to get printed out to a file, but I'll cross that bridge soon
    perldoc -f open, perldoc -f select
      I switched them around and the output didn't change. That's the part that seemed kinda weird to me. To my mind the output would have switched too.
        Switched what around? readdir will return the files in the actual order they are in the directory. AFAIK, most OS's don't give you any control over the actual order (though filesystems based on btrees (NTFS?) will have an automatic order.)
Re: reading files and directories
by crabbdean (Pilgrim) on Jan 07, 2004 at 15:42 UTC
    Peronsally I use like using the File::Find module. It will rip through a directory tree recursively. Along the way each folder it visits you can specify what you want it to do via a referenced subroutine, and it uses several variables such as $File::Find::Dir (current directory) and $_ (filename)and $File::Find::name (full path of file) to refer to what its currently processing. This makes it easy to refer to the files on the fly.

    Dean