File::Path's absolute
doesn't do any file system checks.
use File::Path qw( file );
my $link_qfn = file(...);
my $link_dir_qfn = $link_qfn->dir;
my $target_qfn = $link_dir_qfn->file(readlink($link_qfn));
my $target_fqfn = $target_qfn->absolute;
say $target_fqfn;
Say the CWD is /tmp/perl_script_test/test
$link_qfn ../dir1/link1
$link_dir_qfn ../dir1
$target_qfn ../dir1/../dir2/link2
$target_fqfn /tmp/perl_script_test/test/../dir1/../dir2/link2
Say the CWD is /tmp/perl_script_test
$link_qfn dir1/link1
$link_dir_qfn dir1
$target_qfn dir1/../dir2/link2
$target_fqfn /tmp/perl_script_test/dir1/../dir2/link2
You've added to the following to your question:
I am looking for absolute path of symlink's immediate target without ../
You can't safely do that without possibly resolving symlinks. For example,
/tmp/perl_script_test/dir1/../dir2/link2
is not necessarily equivalent to
/tmp/perl_script_test/dir2/link2
because
/tmp/perl_script_test/dir1
could be a symlink.
The following might be sufficient for you:
use Cwd qw( real_path );
use File::Path qw( dir file );
my $link_qfn = file(...);
my $link_dir_qfn = $link_qfn->dir;
my $target_qfn = $link_dir_qfn->file(readlink($link_qfn));
my $target_fn = $target_qfn->basename;
my $target_dir_qfn = $target_qfn->dir;
my $target_dir_fqfn = dir(real_path($target_dir_qfn));
my $target_fqfn = $target_dir_fqfn->file($target_fn);
say $target_fqfn;
Say the CWD is /tmp/perl_script_test/test
$link_qfn ../dir1/link1
$link_dir_qfn ../dir1
$target_qfn ../dir1/../dir2/link2
$target_fn link2
$target_dir_qfn ../dir1/../dir2
$target_dir_fqfn /tmp/perl_script_test/dir2
$target_fqfn /tmp/perl_script_test/dir2/link2
You will only get the above output if none of the following are symlinks:
/tmp
/tmp/perl_script_test
/tmp/perl_script_test/test
/tmp/perl_script_test/dir1
/tmp/perl_script_test/dir2
(You could make it work even if the first two are symlinks, but that would take even more work.)