in reply to Re: What script is this, and where is it? (Re: who am I?)
in thread who am I?

All of those mechanisms break if the script is being called by a symlink, and particularly so if nested symlinks are involved. You need to readlink($0) if (-l $0) first,

Agreed.

Only FindBin correctly points you to the correct data directory location.

That's wrong.

/var/tmp/otherdir/symdir/../datadir
is the same directory as
/var/tmp/mydir/../datadir

so you demonstrated that working with readlinked $0 works.

even then, it won't give you the same output as FindBin::RealBin.

Doesn't matter.

FindBin is more readable, though.

What good is readable if it doesn't work as well. And I don't see how dirname($script_qn) is less readable than $FindBin::RealBin.

Replies are listed 'Best First'.
Re^3: What script is this, and where is it? (Re: who am I?)
by AZed (Monk) on Sep 24, 2008 at 22:49 UTC

    Edit: claims withdrawn. See below. Original message preserved below the jump.

      *cough* ... look again.

      /var/tmp/otherdir/symdir/../datadir' => '/var/tmp/otherdir/datadir'

      I read it fine the first time.

      /var/tmp/otherdir/symdir/../datadir

      is equivalent to

      /var/tmp/datadir

      and not equivalent to

      /var/tmp/otherdir/datadir

      In "/var/tmp/otherdir/symdir/../datadir", the ".." is that of "mydir" which is a hard link to "/var/tmp".

      Do like I did and test before contradicting someone.

      $ cd /var/tmp $ mkdir mydir $ mkdir datadir $ mkdir otherdir $ touch mydir/in_mydir $ touch datadir/in_datadir $ touch otherdir/in_otherdir $ cd otherdir $ ln -s ../mydir symdir $ ls /var/tmp/otherdir/symdir/../datadir in_datadir $ perl -le'opendir $dh, $ARGV[0] or die; print for grep /in/, readdir +$dh' /var/tmp/otherdir/symdir/../datadir in_datadir
        Ok, so, soon on CPAN (when I have time to write the PODs):
        package File::ScriptName; use strict; use warnings; use version; our $VERSION = qv('0.1'); our $AUTHORITY = 'MASSA'; use Exporter q(import); our @EXPORT_OK = qw(myname mybase mydir); use Carp; use Cwd qw(realpath); use File::Spec::Functions qw(rel2abs); use File::Basename qw(basename dirname); BEGIN { my $myname = $0 = realpath rel2abs $0; my $mybase = basename $0, qw(.t .pm .pl .perl); my $mydir = dirname $0; croak 'chdir() used too early' unless -f $0; sub myname { $myname } sub mybase { $mybase } sub mydir { $mydir } } 1
        Just use $0 (or File::ScriptName::myname) to find the real script name or use File::ScriptName::mybase and File::ScriptName::mydir for whatever purposes you want; traverses all symlinks and stuff... is it enough??
        Update: croaks if you chdir before executing the module (possibly in a BEGIN block). Don't do that.

        UpUpdate:It's on CPAN now, as scriptname...
        []s, HTH, Massa (κς,πμ,πλ)
        Do like I did and test before contradicting someone.

        Huh, okay, that's unexpected, probably because the last time I did this I was dealing with a symlink to a symlink, not a symlink to a real file just in a symlinked directory. I should have used the /tmp example to begin with to avoid confusion.

        Still, my main point holds: dirname(rel2abs($0)) breaks under symlinks, and even a single readlink won't get you out of nested symlinks.

        Realpath works, and dirname(realpath($0)) is consistent, accurate, and clean. I withdraw all prior claims, and will be using this in the future. I don't see the need for a module for it, though I give my thanks to massa for the effort.

        My original test code on rel2abs (with the major bug removed) remains after the jump for the curious.