3John has asked for the wisdom of the Perl Monks concerning the following question:

I have a script that I need to relocate to a new path. The script's guts (C libs that shouldn't be changed) use some code that basically requires the original path name to be there in the C argv[0] (Perl's $0). Let's say /desired/path is the path that the code expects, and /my/newpath is the place I'm trying to run it from.

First I tried:

$0 = "/desired/path";

That worked! But only on some flavors of Linux and not others. The camel book says this isn't portable so that's not too surprising. Then I tried many incarnations of getting execvp to fool the script. My first attempt:

#!/usr/bin/perl                                                                 
                                                                                
use strict;                                                                     
use warnings;                                                                   
                                                                                
my $desired_path = "/desired/path";                                  
if ($0 ne $desired_path) {                                                      
    warn($0);                                                                   
    exec { $0 } $desired_path, @ARGV;                                           
    exit;                                                                       
}                                                                               
                                                                                
warn("Success!");

That infinitely recurses since $0 always appears to be /my/newpath. This behavior as all other behavior that follows seems to be independent of Linux flavor unlike the direct setting of $0.

Suspecting the multiple levels of exec indirection between the shell and Perl I tried;

exec { $^X } $desired_path, $0, @ARGV;

No dice. Same recursion. I tried it right in the shell also:

> exec -a /desired/path /my/newpath

Also no dice. Any advice on how to get this problem solved on most flavors of Linux?

Replies are listed 'Best First'.
Re: Faking Script Names
by shemp (Deacon) on Jul 22, 2005 at 22:29 UTC
    Your problem hinges on the idea that $0 in perl is like $ARGV[0] in C. The perl variable $0 is actually the name of the program that is running. The command line args are stored in @ARGV. So you really want $ARGV[0] (like in c). Try running this code:
    use strict; use warnings; { print "\$0 = $0\n"; print "\$ARGV[0] = $ARGV[0]\n"; }
    Assume that the name of this script is arg_test.pl, run the command:

    >perl -w arg_test.pl foo

    which yields this output:

    $0 = arg_test.pl $ARGV[0] = foo
    The rest of your scripts behaviour should become clear.
      I'm not sure what point is. For starters, $ARGV[0] corresponds to argv[1], not argv[0].
        As yes, my mistake, havent coded any C for many years.
        I use the most powerful debugger available: print!
Re: Faking Script Names
by kwaping (Priest) on Jul 23, 2005 at 00:24 UTC
    Why do you need to move the scripts? I ask because creating a symbolic link in the old location, then running the script using this symlink, will preserve the $0. That is a possible solution if you don't need to wipe out the old path entirely, or something similar that will prevent you from making the symlinks.
      The script is being moved from an nfs mount to someplace local to the box. The nfs mount is going away and the mount point is root owned. Creating ghost paths where nfs used to be isn't going to be an option.
Re: Faking Script Names
by kwaping (Priest) on Jul 23, 2005 at 14:37 UTC
    I don't have access to a box that doesn't support directly setting $0, but try this:
    { local $0 = '/old/path/to/file.pl'; print "$0\n"; #<-- your code here }