2

How to get the cleaned-up absolute path for the perl's executable but with keeping symlinks? (From the $^X variable or anyhow)

example perl executable:

$ ls -l /opt/local/bin/perl
lrwxr-xr-x  1 root  admin  8 18 nov 02:46 /opt/local/bin/perl -> perl5.12

I want get /opt/local/bin/perl in my script regardless how I run the perl interpreter.

The testing code (changesbang.pl):

use strict;
use warnings;
use Cwd;
use File::Spec;
use Config;

my $fmt = "%-25s: %s\n";

printf $fmt, "The value of ^X",        $^X;

printf $fmt, "Cwd::realpath",          Cwd::realpath($^X);
printf $fmt, "Cwd::abs_path",          Cwd::abs_path($^X);

printf $fmt, "File::Spec->cannonpath", File::Spec->canonpath($^X);
printf $fmt, "File::Spec->rel2abs",    File::Spec->rel2abs($^X);

printf $fmt, "Config{perlpath}",       $Config{perlpath};

Now when run the above as

$ ../../../../../opt/local/bin/perl changesbang.pl
The value of ^X          : ../../../../../opt/local/bin/perl
Cwd::realpath            : /opt/local/bin/perl5.12
Cwd::abs_path            : /opt/local/bin/perl5.12
File::Spec->cannonpath   : ../../../../../opt/local/bin/perl
File::Spec->rel2abs      : /Users/jm/Develop/perl/changesbang/../../../../../opt/local/bin/perl
Config{perlpath}         : /opt/local/bin/perl5.12

No one returns me the wanted /opt/local/bin/perl

The question is: how to get the wanted perl's executable path with constrains:

  • should be cleaned up absolute path
  • but if it is the symbolic link, should keep it (don't change it to it's target)

Ps: Here are similar questions like this or this but no one gives me answer.

Community
  • 1
  • 1
clt60
  • 62,119
  • 17
  • 107
  • 194

2 Answers2

2

I suggest you try

use File::Spec::Functions qw( rel2abs canonpath );

print canonpath(rel2abs($^X));

Alternatively, there is

use Cwd::Ext 'abs_path_nd';

print abs_path_nd($^X);
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • running with `../../../../../opt/local/bin/perl prg` returns `/Users/jm/Develop/perl/changesbang/../../../../../opt/local/bin/perl `and not `/opt/local/bin/perl` – clt60 May 04 '13 at 09:45
  • @jm666: Even after putting it through `canonpath`? – Borodin May 04 '13 at 09:47
  • @jm666: I don't have a Linux platform to hand, but I have added another suggestion to my answer. – Borodin May 04 '13 at 09:51
  • Im currently on OS X, but want it portable so nwm. And please, check my code, the Cwd's realpath and abs_path already tried. Thank you anyway, for suggestions :). – clt60 May 04 '13 at 09:53
  • Ah, I apologise. I understand your problem properly now. What you need is the `Cwd::Ext` module. I've modified my answer accordingly. – Borodin May 04 '13 at 09:58
0

What you are asking is impossible to do correctly without resolving symlinks.

/a/b/c/d/e/../../../../../opt/local/bin/perl

is not necessarily the same as

/opt/local/bin/perl

if any of a, b, c, d or e are symlinks. That's why canonpath doesn't change it.

You are seeking to introduce a bug into your program.

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • After i checked the source of Cwd::Ext (what gives what i want) i decided not use it :). Rather I'm steal and modified the Cwd::fast_abs_path to simply ignore all symlinks. I understand what you mean, but for my needs is OK (and desired) ignoring the symlinks (anywhere in the path). The script changing shebang lines (in another perl programs), and (now) works OK when any part of the path is symlink. But, if you can show me any possible problem, will be happy. :) – clt60 May 04 '13 at 17:11