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;