1

Is there an equivalent of shell's "pwd -L" in perl?

I want the current working directory with symlinks unresolved?

My current working directory is "/path1/dir1/dir2/dir3", and here dir1 is symlink to test1/test2. I want current working directory to be "/path1/dir1/dir2/dir3" via perl script. What I am getting is /path1/test1/test2/dir2/dir3.

How can I get the current working directory to be the path with no symlinks resolved? In other words, I would want to implement shell's pwd -L.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
PPP
  • 329
  • 1
  • 9

2 Answers2

2

use the perl backtick operator to run the pwd -L command on your system and capture the output into a variable, this works on my system:

 perl -e 'chomp( my $pwdl = `pwd -L` ); print "$pwdl\n";'
turtle
  • 417
  • 3
  • 11
2

An attempt to replicate the behavior of bash's pwd builtin using just perl (In particular, with the aid of the Path::Tiny and core Cwd modules):

First, from help pwd in a bash shell:

  • -L print the value of $PWD if it names the current working directory
  • -P print the physical directory, without any symbolic links

(The GNU coreutils version of pwd(1) also reads the PWD environment variable for its implementation of -L, which is why running it with qx// works even though it doesn't have access to the shell's internal variables keeping track of the working directory and path taken to it)

$ pwd -P # First, play with absolute path with symlinks resolved
/.../test1/test2/dir2/dir3
$ perl -MCwd -E 'say getcwd'
/.../test1/test2/dir2/dir3
$ perl -MPath::Tiny -E 'say Path::Tiny->cwd'
/.../test1/test2/dir2/dir3
$ pwd -L # Using $PWD to preserve the symlinks
/.../dir1/dir2/dir3
$ /bin/pwd -L
/.../dir1/dir2/dir3
$ PWD=/foo/bar /bin/pwd -L # Try to fake it out
/.../test1/test2/dir2/dir3
$ perl -MPath::Tiny -E 'my $pwd = path($ENV{PWD}); say $pwd if $pwd->realpath eq Path::Tiny->cwd'
/.../dir1/dir2/dir3

As a function (With some added checks so it can handle a missing $PWD environment var or one that points to a non-existent path):

#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;
use Path::Tiny;

sub is_same_file ($$) {
    my $s1 = $_[0]->stat;
    my $s2 = $_[1]->stat;
    return $s1->dev == $s2->dev && $s1->ino == $s2->ino;
}

sub get_working_dir () {
    my $cwd = Path::Tiny->cwd;
    # $ENV{PWD} must exist and be non-empty
    if (exists $ENV{PWD} && $ENV{PWD} ne "") {
        my $pwd = path($ENV{PWD});
        # And must point to a directory that is the same filesystem entity as cwd
        return $pwd->is_dir && is_same_file($pwd, $cwd) ? $pwd : $cwd;
    } else {
        return $cwd;
    }
}

say get_working_dir;
Shawn
  • 47,241
  • 3
  • 26
  • 60