How does : # use perl eval 'exec perl -S $0 ${1+"$@"}' set the perl version?

Viewed 390

I have to debug an old perl script which, apparently, is setting the version of perl in a way which I do not understand...

: # use perl
    eval 'exec perl -S $0 ${1+"$@"}'
    if 0;

perl -h says that -S means "look for programfile using PATH environment variable". $0 is the current program. And I've read that $@ means "The Perl syntax error message from the last eval command." But why are they adding 1 to that ? And how does this all fit together ? What is it doing?

Part of what I have to debug has to do with the fact that it's picking an older version of perl that I don't want. For everything else, we use #!/usr/bin/env perl which, I suspect, may be doing the same thing. I also suspect that my solution may lie in fixing $PATH (or preventing the code that's goofing it up from goofing it up). But I'd like to go at this with a better understanding of how it's picking the version now.

Thanks for any help !

1 Answers

That's intended to run whatever version of perl is first in your path by treating the script first as a shell script that then executes perl. In this context, ${1+"$@"} is the arguments (if any) passed to the script.

From the bash manual:

${parameter:+word}

If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

and

Omitting the colon results in a test only for a parameter that is unset

There's a similar example in perlrun:

This example works on many platforms that have a shell compatible with Bourne shell:

#!/usr/bin/perl
eval 'exec /usr/bin/perl -wS $0 ${1+"$@"}'
  if $running_under_some_shell;

The system ignores the first line and feeds the program to /bin/sh, which proceeds to try to execute the Perl program as a shell script. The shell executes the second line as a normal shell command, and thus starts up the Perl interpreter. On some systems $0 doesn't always contain the full pathname, so the -S tells Perl to search for the program if necessary. After Perl locates the program, it parses the lines and ignores them because the variable $running_under_some_shell is never true. If the program will be interpreted by csh, you will need to replace ${1+"$@"} with $*, even though that doesn't understand embedded spaces (and such) in the argument list. To start up sh rather than csh, some systems may have to replace the #! line with a line containing just a colon, which will be politely ignored by Perl.

Using /usr/bin/env is another way to do the same thing, yes.

Related