Search code examples
shellperlshebang

What does "#! -*-perl-*-" mean?


In the perl documents one can read:

Parsing of the #! switches starts wherever "perl" is mentioned in the line. The sequences "-*" and "- " are specifically ignored so that you could, if you were so inclined, say

#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS $0 ${1+"$@"}'
    if 0; to let Perl see the -p switch.

to let Perl see the -p switch.

I'm confused about the comment. The line "--perl--" is inside a comment, and shebang has already been parsed. If I write:

!/bin/sh
#! -*-python-*-
print 1

It doesn't work. Also, those sequences are always ignored? Does it mean that that is something similar to '/bin/sh -perl'? That fails on the terminal.

Then it also mentions the "-p" switch. But there is no p switch in the code.


Solution

  • Your quote is incompletely copied. The text actually says

    Parsing of the #! switches starts wherever "perl" is mentioned in the line. The sequences -* and - are specifically ignored so that you could, if you were so inclined, say

    #!/bin/sh --
    #! -*- perl -*- -p
    eval 'exec perl $0 -S ${1+"$@"}'
        if 0;
    

    to let Perl see the -p switch.

    There are three things at play here.

    • The #!/bin/sh shebang causes the script to be run by sh. The eval 'exec ...' stuff is a hack to force sh to exec perl if that happens.
    • The -*- perl -*- specifier is an Emacs mode string. But it also coincidentally triggers the next behavior.
    • The second #! together with the perl text from the previous item are what trigger the described option parsing. As per the parsing rules, the mode string is ignored, and the -p at the end of that line gets picked up as the actual option for Perl.

    The preceding paragraphs in the documentation should perhaps also be quoted for context:

    As of Perl 5, the #! line is always examined for switches as the line is being parsed. Thus, if you're on a machine that only allows one argument with the #! line, or worse, doesn't even recognize the #! line, you still can get consistent switch behavior regardless of how Perl was invoked, even if -x was used to find the beginning of the script.

    Because many operating systems silently chop off kernel interpretation of the #! line after 32 characters, some switches may be passed in on the command line, and some may not; you could even get a - without its letter, if you're not careful. You probably want to make sure that all your switches fall either before or after that 32 character boundary. Most switches don't actually care if they're processed redundantly, but getting a - instead of a complete switch could cause Perl to try to execute standard input instead of your script. And a partial -I switch could also cause odd results.

    ... And later on:

    If the #! line does not contain the word "perl", 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.