How does Perl handle the shebang line?

2019-07-16 03:38发布

问题:

I'm trying to understand how perl deals with the shebang line.

I used to think that any interpreter mentioned in the "command position" on the command line would take precedence over one mentioned in the shebang line. For example, if an executable script called demo looks like this

#!/usr/local/bin/perl-5.00503

printf "$]\n";

...then I would observe the following:

$ ./demo
5.00503
% /usr/local/bin/perl-5.22 ./demo
5.022003

IOW, in the first execution, the interpreter in the shebang is the one running, while in the second it is the one mentioned on the command line. So far so good.

But now, if I change the "interpreter" on the shebang to something like /usr/bin/wc, then it always beats any perl interpreter I mention on the command line:

% cat demo-wc
#!/usr/bin/wc

printf "$]\n";

% ./demo-wc                           # produces the expected behavior
       4       3      31 ./demo-wc
% /usr/local/bin/perl-5.22 ./demo-wc
       4       3      31 ./demo-wc
% /usr/local/bin/perl-5.14 ./demo-wc
       4       3      31 ./demo-wc

AFAICT, this special behavior seems to be limited perl interpreters; non-perl interpreters, such as /bin/bash, do "overrule" the shebang:

% /bin/bash ./demo-wc
$]

The bottom line is that perl seems to have radically different policies for handling the shebang depending on the interpreter mentioned.


  1. How does perl determine which policy to follow?
  2. What exactly are the policies in either case?

回答1:

There are a couple of different cases in your tests.

When you use ./demo... the kernel finds the #! in the magic number (first 16 bits) and runs that program, or passes the line to the shell if it fails, which starts what's on it.

But when you invoke a perl on the command line, that perl binary is started by the shell and then that perl interpreter itself processes the shebang. In this case it discards the perl part but takes account of the switches – if the line contains "perl".

If the shebang does not invoke perl, we have behavior special to Perl. From 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.



回答2:

Unlike most other interpreters, perl does its own processing of the #! line. This enables it to take multiple option arguments, even though the kernel's #! handler will only pass a single string.

Details are in the perlrun man page. The relevant portion for you is this:

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.