in reply to who am I?

I avoid FindBin since the it has problems. There are easy to use alternatives:

Script's Path
(Fully Qualified)
use Cwd qw( realpath ); $script_fqn = realpath($0);
Script's Name
use File::Basename qw( basename ); $script_fn = basename($0);
Script's Dir
(Fully Qualified)
use Cwd qw( realpath ); use File::Basename qw( dirname ); $script_dir_fqn = dirname(realpath($0));

Update: I originally use File::Spec::Functions's rel2abs, but it doesn't handle symlinks properly. I've updated the table to use Cwd's realpath which does, as per replies.

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

    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, and then check, and even then, it won't give you the same output as FindBin::RealBin.

    Create the following directory structure in /var/tmp. Set up directories as follows (you'll need root for /usr/local/bin, so feel free to make the last step anywhere else in your path that you'd like):

    cd /var/tmp mkdir mydir mkdir datadir mkdir otherdir cd otherdir ln -s ../mydir symdir
    Now take the following code and put it in /var/tmp/mydir/myname.pl:
    #!/usr/bin/perl use strict; use warnings; use FindBin; use File::Basename qw( dirname ); use File::Spec::Functions qw( rel2abs ); my $name = $0; $name = readlink($name) if(-l $name); print "Finding a data path:\n\n"; print 'dirname($name):',dirname($name),"/../datadir\n"; print 'dirname(rel2abs($name)):',dirname(rel2abs($name)),"/../datadir\ +n"; print 'dirname($0):',dirname($0),"/../datadir\n"; print 'dirname(rel2abs($0)):',dirname(rel2abs($0)),"/../datadir\n"; print '$FindBin::RealBin:',$FindBin::RealBin,"/../datadir\n";

    Symlink /var/tmp/symdir/myname.pl to /usr/local/bin/myname (or somewhere else on your path, if you can't or don't want to tamper with a system directory). Run 'myname'. You get:

    Finding a data path: dirname($name):/var/tmp/otherdir/symdir/../datadir dirname(rel2abs($name)):/var/tmp/otherdir/symdir/../datadir dirname($0):/usr/local/bin/../datadir dirname(rel2abs($0)):/usr/local/bin/../datadir $FindBin::RealBin:/var/tmp/mydir/../datadir

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

    Frankly, even without symlink forests, FindBin is more readable, though.

      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.

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

Re: What script is this, and where is it? (Re: who am I?)
by Anonymous Monk on Sep 25, 2008 at 06:45 UTC
    rel2abs doesn't have a problem with symlinks as No checks against the filesystem are made. , it simply uses Cwd::cwd() as the base (rel2abs($path,$base)).
      That it doesn't check against the file system is the problem. The goal is to find a file or directory relative to the placement of the script, not relative to the placement of a shortcut to the script.