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

I have what I believe is one of the simplest of question but am having a lot of trouble figuring out what is going on. Here is the issue:

I am running on Windows XP and am trying to do a simple directory traversal task. I have done this many, many times on Unix systems but have, surprising to myself, never done it on a Windows XP system.

I do a simple file test, of the form:

if( -d $entry ) {do something}else{do something else}

The problem is that this never identifies anything as a directory (i.e., only the "do something else" clause gets executed.

I know that when it comes to Win32 systems there are some special considerations, especially regarding the file & directory handling strategies, but this one puzzles me.

I have searched on the web for Perl and Window XP and have seen a lot of special considerations and have looked to resources such as the "Learning Perl on Win32...." But I can't find anything that says why (or even that) this doesn't work.

I'm not interested in wasting anyone's time; this is not worthy of any such effort. I'm just looking for a nudge or two about where I might look for more information on unique issues/considerations on using Perl on Win32 systems.

Also, I know that there are plenty of Modules out on CPAN that will solve the problem; I'm just looking to understand "what's under the hood" so to speak on Perl and Win32 on file test operations.

This issue really tripped me up. It leaves me feeling really stupid (probably for good reason); but I really like to understand what's going on so that I can better handle these things for myself in the future...and to better appreciate all that the CPAN modules bring to my efforts.

UPDATE: Thanks to everyone. Seems like the general consensus is that I'm not in the directory that I think I'm in.

Also, most everyone suggested that I post some of the code so that it could be clearer what I'm experiencing. I shoud have done that when I posted (my bad); I appologize for not doing so.

I thought the problem would be so easy to spot that the rest of the code would just clutter up the posting. But I see that my reasoning was incorrect.

I have provided the code below...it's not too long.

What I'm trying to do is to get a count of all the pictures I have in a particular directory (which I specify in the $top_directory variable...I set it to a full path name). I go to that directory, read in all its contents and then one-by-one check to see if the entry is a directory (which I would then traverse in recursive style, depth-first.

It is that directory check that is giving me trouble.

Here is the code. I have abbreviated it to focus on what I believe is the essential infomration.

UPDATE 2:

Sorry, I should have noted that the code below is extracted from my picture counting code. I have deleted all of the log file handling and specific counting steps. I have reduced the code to the essence of what is failing. In the below-provided code, I simply try to print out a statement indicating when I find a directory entry in the top directory. Even though there are sub-directories in this top directory, none ever gets put into the printout.

Here is the code...

#!/usr/bin/perl use strict; use warnings; my $top_dir = "C:/Documents and Settings/Owner/My Documents/My Picture +s"; $top_dir = $top_dir . "/ACK_Kenya_2008/"; opendir(THISDIR,$top_dir) || die "$0: Can't open directory '$top_dir': $!\n"; my @file_list = readdir(THISDIR); # slurp in all directory entries closedir(THISDIR) || die "$0: Can't closer current directory '.': $!\n"; my $tot_count = 0; my $line = " PICTURES\n"; foreach my $this_file (@file_list) { next if($this_file =~ /^\.{1,2}$/); # ignore the . and .. entries my $file = $top_dir . $this_file; # be sure to use file with full + path name if(-d $file) { print "$this_file is a directory\n"; } # end if } # end foreach $file loop exit(0);
ack Albuquerque, NM

Replies are listed 'Best First'.
Re: Directory checking on Windows XP
by moritz (Cardinal) on Sep 11, 2008 at 18:14 UTC
    The usual suspect is that you're not in the directory you think you are in. Use the functions from the Cwd module (it's core) to check if that's the case.

      Thank you, moritz, for you kind response. I apprecaite it very much, indeed.

      Turns out that my mistake was that I forgot to chomp() $entry before testing. apl suspected that could be the problem and, indeed, when I added that in, everything works just fine.

      It was such a rookie mistake and is one that I am embarassed to have made. I didn't realize that readdir() would put in the extra characters; but apparently it does.

      I just too focused on the details of what was being put into $entry (in terms of the interior characters) that I forgot to look at what was at the end. As part of my troubleshooting I normally am careful to put some sort of bracketing character (e.g., [ and ]) just for that very purpose. I broke my own process; and am embarassed at the consequences!

      Thank you, most sincerely, to everyone that responded. Your patience, help, and gentle responses were most kind. Your time and efforts are most appreciated.

      ack Albuquerque, NM
Re: Directory checking on Windows XP
by apl (Monsignor) on Sep 11, 2008 at 18:17 UTC
      ,p>Bingo!

      I forgot to chomp($entry)!

      What a rookie mistake I made! Thank you. I was thinking that readdir() didn't put CRLFs in...but apparently it does. When I added in the chomp($entry) the code works perfectly!

      Even while debugging I failed to see the extra characters; I was too focused on the non-CRLF names and characters...looking for unexpected included extra spaces, etc.

      Thank you apl. And thanks to everyone who responded. Your support and time mean the world to me and I am sincerely embarassed by my mistake and appreciate your time and efforts.

      ack Albuquerque, NM

        chomp removes $/ which is just LF, not CRLF. Yes, even on Windows. So chomp wouldn't fix appended CRLF, just appended LF.

        use Data::Dumper; $Data::Dumper::Terse = 1; $Data::Dumper::Useqq = 1; print(Dumper($/)); # "\n" $_ = "abc\x0D\x0A"; print(Dumper($_)); # "abc\r\n" chomp; print(Dumper($_)); # "abc\r"

        But readdir doesn't append CRLF or LF to the file names it returns. Not unless you have a broken perl.

        >copy nul foo 1 file(s) copied. >copy nul bar 1 file(s) copied. >perl -e"opendir $dh, '.' or die; print readdir $dh" ...barfoo

        Tested with Perl 5.6.0, 5.6.1, 5.8.0, 5.8.8 and 5.10.0.

Re: Directory checking on Windows XP
by ikegami (Patriarch) on Sep 11, 2008 at 21:54 UTC
    If what you say is true, you have a very broken Perl.
    >md dir >copy nul file 1 file(s) copied. >perl -le"if (-d $ARGV[0]) { print 'dir' } else { print 'not' }" dir dir >perl -le"if (-d $ARGV[0]) { print 'dir' } else { print 'not' }" file not

    I could see the opposite (always getting the else part) due to being in a different working directory than you think you are, having trailing whitespace in your file name or attempting to use wide file names.

    Update: Oops, I read it backwards. You are getting the else part.

      Thanks ikegami. I posted an update to my node and included an abbreviated portion of the code that I think demonstrates what I'm doing. It is not the full code; but think it highlights what and how I'm doing the if(){}else{} statement. Hopefully it will prompt someone to see what is happening.

      I have tried debugging the code; but it just shows that the }else{ portion of the code is, indeed, what is being executed. I have checked what is in $entry and it has the right subdirectory name (includindg the full path specification).

      Is specifing the full path name in $entry what is fowling up the -d file test?

      ack Albuquerque, NM

        Is specifing the full path name in $entry what is fowling up the -d file test?

        No, that's fine. Absolute and relative paths are accepted.

        In fact, nothing is fowled up. Your code works fine.

        bar is a directory foo is a directory sub folder is a directory

        Are you sure "ACK_Kenya_2008" and this directory are really folders and not shortcuts?

Re: Directory checking on Windows XP
by BrowserUk (Patriarch) on Sep 13, 2008 at 08:12 UTC

    What is in $entry?

    If for example, $entry is being obtained from an environment variable set up manually using tab completion to generate the path like this:

    set SOME_ENV_VAR="c:\some\path"

    Where most native programs and utilities will accept and ignore/discard the quotes, Perl doesn't. Getting rid of the quotes in the environment variable will fix the problem.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Excellent question. I have posted an update to my original node and have included the code.

      $entry specifies and entry from a directory with a full directory path name...for example as follows (NOTE: THISDIR is the directory handle from an opendir() on the $top_dir):

      $top_dir = "C:/Blah/"Blah Smah"/Blahdie/"; @all_entries = readdir(THISDIR); foreach my $the_entry (@all_entries) { $entry = $top_dir . $the_entry; if(-d $entry) { <do something> } else { <do something else> } }
      ack Albuquerque, NM
Re: Directory checking on Windows XP
by GrandFather (Saint) on Sep 11, 2008 at 21:03 UTC

    I have used -d (and many of the other file test operators) frequently on Windows systems and can assure you that they work. Perhaps you could post a little code that demonstrates the problem?

    The most likely issue is that the file path you are testing is not relative to where you think it is. "Wibble/plonk.pl" refers to the file plonk.pl in the Wibble directory relative to the current working directory. (You might notice btw that Windows generally doesn't mind / being used in place of \.)


    Perl reduces RSI - it saves typing

      Thanks, GrandFather, for your response. I appreciate it very much. As with all the other responders, your wisdom always helps me to grow.

      I posted an update to my node and included, as most of the responders wisely suggested, a block of code to illustrate what I am inquiring about. It is not, of course, the full code; but I think it highlights in a way that portrays what I am doing.

      I am including in $entry the full directory path specification, so I'm not clear on why the test would fail if I'm executing the code in a directory different from the one I'm trying to process. But I presume I'm not actually doing what I think I am doing...which is what has me perplexed.

      I am confident that the -d filetest operator is working properly and that it works just fine on Windows (as you most appropriately noted from your own experience). So I'm likewise confident that I'm doing something wrong.

      As I noted in response to another's monk's response, I've tried the code through the debugger and $entry checks out with the proper full path specification. And, of course, I can't see with the debugger what the -d function thinks it is seeing other than the value of $entry. It does, of course, also confirm that it is the }else{ clause that gets executed.

      ack Albuquerque, NM