in reply to Surprising behavior of Cwd module on Unix with symlinks

Cwd's getcwd simply returns what the system provides. Your shell is actually tracking the work directory separately from the system, but it provides it via $ENV{PWD}. You can use it safely as follows:

use Cwd qw( getcwd ); sub my_getcwd { use Cwd qw( ); sub getcwd { my $cwd = Cwd::getcwd(); if (exists($ENV{PWD}) && $ENV{PWD} ne $cwd) { my $e = my ($e_dev, $e_node) = stat($ENV{PWD}); my $c = my ($c_dev, $c_node) = stat($cwd); if ($e && $c && $e_dev == $c_dev && $e_node == $c_node) { $cwd = $ENV{PWD}; } } return $cwd; } print Cwd::getcwd(), "\n"; print getcwd(), "\n";
/tmp/ikegami /home/ikegami/tmp

Replies are listed 'Best First'.
Re^2: Surprising behavior of Cwd module on Unix with symlinks
by DrHyde (Prior) on Feb 08, 2011 at 10:53 UTC
    $ENV{PWD} has the same portability problems as `pwd` does though, and the OP was specifically looking for a portable solution to the problem.

      Getting bash's pwd isn't possible where bash isn't used. What's your point? Are you implying that the code I posted isn't portable? If so, you'd be mistaken.

      Update:

      Every tool that gives you bash's pwd use $ENV{PWD}.

      $ /bin/pwd GNU pwd /tmp/ikegami $ bash -c pwd bash's builtin /home/ikegami/tmp $ PWD=/ bash -c pwd bash's builtin uses $ENV{PWD} /tmp/ikegami

      The GNU pwd doesn't have any command line options and always gives the path returned by getcwd (with a fallback on error). Darwin's pwd goes a step further and does something that looks awfully familiar.

      static char * getcwd_logical(void) { struct stat lg, phy; char *pwd; /* * Check that $PWD is an absolute logical pathname referring to * the current working directory. */ if ((pwd = getenv("PWD")) != NULL && *pwd == '/') { if (stat(pwd, &lg) == -1 || stat(".", &phy) == -1) return (NULL); if (lg.st_dev == phy.st_dev && lg.st_ino == phy.st_ino) return (pwd); } errno = ENOENT; return (NULL); }

        The portability problem with $ENV{PWD} is that it assumes Unix. `pwd` also assumes Unix. The OP said "though I could replace the Cwd::cwd() calls with `pwd` (for Unix only), I'd prefer a more portable solution."

        In addition, $PWD isn't a bashism. csh and ksh also populate it.