Should Perl's opendir always return . and .. first?
Asked Answered
O

3

10
  opendir MYDIR, "$dir";
  my @FILES = readdir MYDIR;
  closedir MYDIR;

It appears that 99.9 % of the time the first two entries in the array are always “.” and “..”. Later logic in the script has issues if it is not true. I ran into a case where the directory entries appeared later. Is this indicative of the file system being corrupt or something else? Is there a known order to what opendir returns?

Ornery answered 16/4, 2010 at 15:41 Comment(0)
S
21

It's always the operating-system order, presented unsorted raw.

While . and .. are very often the first two entries, that's because they were the first two entries created. If for some reason, one of them were deleted (via unnatural sequences, since it's normally prevented), the next fsck (or equivalent) would fix the directory to have both again. This would place one of the names at a later place in the list.

Hence, do not just "skip the first two entries". Instead, match them explicitly to reject them.

Stereotaxis answered 16/4, 2010 at 15:46 Comment(3)
How exactly would they get deleted? Can you describe one of those unnatural sequences?Ornery
I think he means that something has to go wrong, since it's normally prevented. If an fsck fixes it, that implies corruption to me. One instance I can imagine where this might happen is where a parent directory is deleted or lost, and it's contents were not (corruption or failed operation). If it was restored in an fsck, that would result in a later placement of ".." in it's subdirectories, I imagine.Ordain
There are filesystems that don't store directory entries in an ordered list, and that don't return . and .. at any particular position under normal operation. For example, ext3/ext4 with B-trees enabled, which is used on most recent-ish Linux installations.Schrock
T
8

The order is down to the OS and is explicitly not otherwise defined.

They're easy enough to filter out.

   opendir MYDIR, "$dir";
   my @FILES = grep !/^\.\.?$/, readdir MYDIR  ;
   closedir MYDIR;
Thereupon answered 16/4, 2010 at 16:35 Comment(3)
I'd change your regex for betterr eadability a bit: my @FILES = grep !/^[.]{1,2}$/, readdir MYDIR;Tudor
@Tudor I actually like ^[.][.]?\z, but then I am weird like that. Just make sure you anchor at the end of the string using \z not $.Vandusen
Yes... beware that /^\.\.?$/ also matches "..\n", which is a legal name that you do not want to skip.Stereotaxis
L
6

Use File::Slurp::read_dir which, by default, returns a list that does not include . and ...

Lexine answered 16/4, 2010 at 17:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.