7

Many of my colleagues use the following commands in their BEGIN block.

$scriptDir = dirname($0);
chdir($scriptDir);
$scriptDir =  getcwd();

I have looked around and can't help but think that the third line i.e. $scriptDir = getcwd(); is redundant. Because we already have the scriptdir from $scriptDir = dirname($0); .Am I missing something here ?

tarunkt
  • 186
  • 12
  • As shown below, `use FindBin qw( $RealBin );` and do not change directory. Files listed in `@ARGV` are relative to `pwd`, not `$RealBin`. – shawnhcorey Dec 23 '16 at 15:42

3 Answers3

7

The dirname($0) does not return the full path, as Chankey Pathak and Matthias demonstrate.

I'd like to add that there are other ways. For example, you can use FindBin (also core)

use FindBin qw($RealBin);

BEGIN: {
    my ($scriptDir) = $RealBin;
    chdir $scriptDir             or die "Can't change to $scriptDir: $!";
};

The $RealBin gives the same as what you show, except that it is the full path with links resolved.

The chdir may fail, thanks to ikegami for the comment. In that case false is returned and the code above dies, adjust as suitable. Note that the questioned third line has nothing to do with this.

This module is also commonly used for relative path to libraries with lib pragma, for example

use lib "$RealBin/../lib";

what perhaps makes for an even easier decision to use it for both.


Even more, given the dirname description from File::Basename (original emphasis)

This function is provided for compatibility with the Unix shell command dirname(1) and has inherited some of its quirks. In spite of its name it does NOT always return the directory name as you might expect. To be safe, if you want the directory name of a path use fileparse().

I would rather go even with

use Cwd qw(abs_path);

BEGIN: {
    my ($scriptDir) = abs_path(__FILE__) =~ m|(.*)/|;
    chdir $scriptDir             
        or die "Can't change to $scriptDir: $!";
};

where abs_path is used since __FILE__ on its own may not provide the full path. The regex greedily scoops everything up to the very last /, that is, the full path to the directory of the script.

zdim
  • 53,586
  • 4
  • 45
  • 72
4
  • getcwd - Returns the current working directory
  • chdir - Changes the working directory to EXPR

Below example explains it well.

#!/usr/bin/perl
use strict;
use warnings;
use File::Basename;
use Cwd;

my $scriptDir = dirname($0);
chdir($scriptDir);
print "First: $scriptDir\n";
$scriptDir =  getcwd();
print "Second: $scriptDir\n";

Output:

chankeypathak@stackoverflow:~/Desktop$ perl test.pl 
First: .
Second: /home/chankeypathak/Desktop
Chankey Pathak
  • 19,330
  • 10
  • 72
  • 119
0

I am not the next perl monger, but I have tried to execute the code you gave with a little script:

#!/usr/bin/perl
# 

use strict;
use File::Basename;
use Cwd;

BEGIN {
  my $scriptDir = dirname($0);
  print "scriptDir = $scriptDir\r\n";
  chdir($scriptDir);
  $scriptDir =  getcwd();
  print "scriptDir = $scriptDir\r\n";
}

And this is what came out:

map@host:~/perltest> ./script.pl 
scriptDir = .
scriptDir = /home/map/perltest
map@host:~/perltest> 

It looks as if dirname and getcwd make a difference in this case. If however scrip.pl is found in path there is no difference:

map@host:~> cp script.pl ~/bin
map@host:~> cd
map@host:~> script.pl
scriptDir = /home/map/bin
scriptDir = /home/map/bin
map@host:~> rm ~/bin
Matthias
  • 3,228
  • 2
  • 23
  • 40