Gregory Nisbet Gregory Nisbet - 5 months ago 22
Perl Question

How does Perl avoid shebang loops?

perl
interprets the shebang itself and mimics the behavior of
exec*(2)
. I think it emulates the Linux behavior of splitting on all whitespace instead of BSD first-whitespace-only thing, but never mind that.

Just as a quick demonstration
really_python.pl


#!/usr/bin/env python

# the following line is correct Python but not correct Perl
from collections import namedtuple
print "hi"


prints hi when invoked as
perl really_python.pl
.

Also, the following programs will do the right thing regardless of whether they are invoked as
perl program
or
./program
.

#!/usr/bin/perl
print "hi\n";


and

#!/usr/bin/env perl
print "hi\n";


I don't understand why the program isn't infinite looping. In either of the above cases, the shebang line either is or resolves to an absolute path to the
perl
interpreter. It seems like the next thing that should happen after that is
perl
parses the file, notices the shebang, and delegates to the shebang path (in this case itself). Does
perl
compare the shebang path to its own
ARGV[0]
? Does
perl
look at the shebang string and see if it contains
"perl"
as a substring?

I tried to use a symlink to trigger the infinite loop behavior I was expecting.

$ ln -s /usr/bin/perl /tmp/p

#!/tmp/p
print "hi\n";


but that program printed "hi" regardless of how it was invoked.

On OS X, however, I was able to trick
perl
into an infinite shebang loop with a script.

Contents of
/tmp/pscript


#!/bin/sh
perl "$@"


Contents of perl script

#!/tmp/pscript
print "hi\n";


and this does infinite loop (on OS X, haven't tested it on Linux yet).

perl
is clearly going to a lot of trouble to handle shebangs correctly in reasonable situations. It isn't confused by symlinks and isn't confused by normal
env
stuff. What exactly is it doing?

Answer

The documentation for this feature is found in perlrun.

If the #! line does not contain the word "perl" nor the word "indir", the program named after the #! is executed instead of the Perl interpreter. This is slightly bizarre, but it helps people on machines that don't do #!, because they can tell a program that their SHELL is /usr/bin/perl, and Perl will then dispatch the program to the correct interpreter for them.

So, if the shebang contains perl or indir, a new interpreter isn't executed.

Additionally, the interpreter isn't executed if it's the same as $^X. How $^X is set varies by system, explaining the differences you observed.

Comments