I recently wrote a script that modifies files and copies them to a different directory. The user can specify on the command line the source and target directories, but I needed to ensure that those directories are different. For example, when running my script, -s specifies the source and -d specifies the destination, but the following command uses the same directory, despite being superficially different:
prod.pl -an -s . -d ../cgi-bin
It seems like a bit of an ugly hack, so if anyone knows of a module with similar functionality, please speak up!

This was written for a WinNT box. Any suggestions for ensuring portability?

Update: This is what I love about this place: see AltBlue's answer below. Short, sweet, and to the point. More importantly, it shows that I should have read the Cwd docs more closely :)

#C:\perl\bin\perl.exe use warnings; use strict; use Cwd; my $source = '.'; my $target = '../cgi-bin'; print sameDirectory( $source, $target ) ? 'Same' : 'Different'; sub sameDirectory { my ( $dir1, $dir2 ) = @_; my $currentDir = getcwd(); chdir $dir1 or die "Can't CD to $dir1: $!"; my $realDir1 = getcwd(); # Need to change back in case they were using relative directories chdir $currentDir or die "Can't CD to $currentDir: $!"; chdir $dir2 or die "Can't CD to $dir2: $!"; my $realDir2 = getcwd(); # Return them to their home directory chdir $currentDir or die "Can't CD to $currentDir: $!";; return $realDir1 eq $realDir2 ? 1 : 0; }

Replies are listed 'Best First'.
Re: Test to see if directories are the same
by chipmunk (Parson) on Jan 17, 2001 at 23:00 UTC
    Here's a simple way to test if two paths point to the same file or directory, using stat:
    sub matching_paths { my($path1, $path2) = @_; my(@stat1) = stat $path1; my(@stat2) = stat $path2; return $stat1[0] == $stat2[0] && $stat1[1] == $stat2[1]; }
    (stat)[0, 1] are the device number and the inode number, which together uniquely identify a file or directory.

    I don't know how portable this solution is, however.

      Or, a bit more obscure but very cool:
      sub same_file_p { my @stat1 = stat shift; my @stat2 = stat shift; return "@stat1[0,1]" eq "@stat2[0,1]"; }
      And even weirder:
      sub all_same_file { # true if all arguments represent the same file my %counts; $counts{join " ", (stat)[0,1]}++ for @_; 1 == keys %counts; }

      -- Randal L. Schwartz, Perl hacker

        Inode numbers are not reported on Windows so the above is OS-specific, as is this version:
        sub all_same_file { my @desc = map {my @s = stat; "@s[0,1]"} @_; @_ == grep {$desc[0] eq $_} @desc; }

        And slightly weirder:

        sub all_same_file { join(" ",map{(stat)[0,1]}@_) =~ /^(\d+ \d+) (\1 ?){$#_}$/; }
Re: Test to see if directories are the same
by AltBlue (Chaplain) on Jan 18, 2001 at 00:07 UTC
    if you have Cwd on win32 than this should work:
    sub sameDirectory { my ($s,$d) = @_; -d $s and $s = abs_path($s) or return -1 ; -d $d and $d = abs_path($d) or return -1 ; $s eq $d ? 1 : 0 ; }

    --
    AltBlue.

      Note that this doesn't work in the face of symbolic links (or in the face of file systems that support hard links to directories better than most Unix file systems do).

      Perhaps someone should combine the two sets of tests into one that works lots of places. I'd personally prefer testing for 0 == (stat($d))[1] over trying to hard-code some list of $^O values (or are there file systems where i-node 0 might be a valid directory?).

              - tye (but my friends call me "Tye")
        no idea if it'd be working against hardlinks (don't any OS that can do that :( ), but it sure does with symlinks :) .. it's written in Cwd docs:
        The abs_path() function takes a single argument and returns the absolute pathname for that argument. It uses the same algorithm as getcwd(). (Actually, getcwd() is abs_path(".")) Symbolic links and relative-path components ("." and "..") are resolved to return the canonical pathname, just like realpath(3). Also callable as realpath().

        ... ofc, cause you mentioned it i've just tested it and seems to be working ok on linux and sunos.

        --
        AltBlue.

        I did some limited tests and did note that on RedHat 6.2 I got positive results with symbolic links. I just did a quick check on NT with the base test.
        Cwd.pm does run it's own $^O checks, so it may be workable on most cases.
      -d $s and $s = abs_path($s) or return -1 ; -d $d and $d = abs_path($d) or return -1 ;
      Don't write the same code twice. Ever. :)
      -d $_ and $_ = abs_path($_) or return -1 for $s, $d;
      Except that's using "foo AND bar OR bletch" where it should be using "foo ? bar : bletch", so I'd tighten that up to:
      (-d $_) ? ($_ = abs_path($_)) : (return -1) for $s, $d;

      -- Randal L. Schwartz, Perl hacker

        merlyn: Don't write the same code twice. Ever. :)
        oops. sorry :))

        this gave me an idea: why not give ppl a way to compare N directories? :) here is the test code:

        #!/usr/bin/perl -w use strict; use Cwd 'abs_path'; defined @ARGV and print sameDirectory(@ARGV),$/; sub sameDirectory { (-d) ? $_ = abs_path $_ : return -1 for @_; $_[0] ne $_ and return 0 for @_; 1; }

        --
        AltBlue.