http://www.perlmonks.org?node_id=486550

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

which perl is an oft discussed subject, but I can't determine the reason for the observed behavior as follows --

On my Mac, I finally did the way I should have always done it... started with a clean machine (OS X 10.3 with perl v5.8.1-RC3), left the stock perl alone, installed Activestate perl v5.8.7 under usr/local/Activestate..., linked the AS perl to ~/bin/perl, and changed my shebang lines to #!/Users/punkish/bin/perl.

[mumbai:~/Sites/test] punkish% which perl /usr/bin/perl [mumbai:~/Sites/test] punkish% perl -v This is perl, v5.8.1-RC3 built for darwin-thread-multi-2level .. [mumbai:~/Sites/test] punkish% ~/bin/perl -v This is perl, v5.8.7 built for darwin-thread-multi-2level .. [mumbai:~/Sites/test] punkish% perl -c test.pl Can't locate CGI/Simple.pm in @INC (@INC contains: /System/Library/Per +l/5.8.1/darwin-thread-multi-2level /Syste.. [mumbai:~/Sites/test] punkish% ./test.pl Content-Type: text/html; charset=ISO-8859-1 <style type="text/css"> .strike {text-decoration:line-through;} .hilite .. [mumbai:~/Sites/test] punkish% ~/bin/perl ./test.pl Content-Type: text/html; charset=ISO-8859-1 <style type="text/css"> .strike {text-decoration:line-through;} .hilite ..

So, in the terminal I get the factory-installed perl because it is in the path, while my own perl is not in the path. I can even understand why the shebang line is ignored when I call perl test.pl (although it seems that the purpose of the shebang line is defeated -- "what is the purpose of the shebang line?"). But, to confirm the "sense" of the behaviour, shebang line comes into play only when the perl interpreter is not called directly?

Interestingly, while #!/Users/punkish/bin/perl works, and ~/bin/perl test.pl works, #!~/bin/perl fails. So, seems like shell expansion of ~ is not done in a shebang line.

--

when small people start casting long shadows, it is time to go to bed

Replies are listed 'Best First'.
Re: #! -- why doth thou exist?
by Tanktalus (Canon) on Aug 25, 2005 at 13:45 UTC

    #! is the "magic number" for interpreted languages. The kernel looks at your file that you're trying to run, and determines what "mode" to run it in. (Some OS's only support a single binary type, but many support multiple - e.g., ELF and libc formats on Linux, or Win32, Win16, and OS/2-16 on Windows, etc.) One of these modes, on unix systems anyway, is the "interpreted" mode where the kernel reads that first line, and calls that executable on the file instead.

    So, when you run "./test.pl", the kernel looks at your file and sees the #! magic number, and then reads the line, sees to run "/Users/punkish/bin/perl ./test.pl", and does so. In turn, it looks at /Users/punkish/bin/perl, sees that its magic number is a binary native to MacOSX, knows how to run it, and does so.

    However, the kernel does not know what ~ is - that's something your shell knows how to interpret. If you're on the commandline, the shell replaces that character before passing it to the kernel, while if it's in the #! line, the kernel doesn't know how to deal with it, and aborts running the file.

    Welcome to unix :-)

      Tanktalus++

      My commendations for a most excellently lucid explanation.

      My thanks to everyone else as well.

      --

      when small people start casting long shadows, it is time to go to bed
Re: #! -- why doth thou exist?
by itub (Priest) on Aug 25, 2005 at 13:56 UTC

    The shebang line is not interpreted by the shell. It's used by the operating system kernel to figure out how to execute a file that has the executable bit on and is not a "real" binary executable. I believe it goes more or less like this:

    You (maybe via a shell)
    Hey, OS! Please execute ./test.pl
    OS
    Hm, this doesn't look like a binary, but it starts with #!. Let's see... Oh, I should tell /usr/bin/perl to handle it. (executes /usr/bin/perl)
    OS
    Hey, perl, there you are! Run with ./test.pl as your first argument (some systems might include all arguments from the shebang line at this stage).
    perl
    (Opens ./test.pl). Hey, this looks like a Perl program with a shebang line! Let's see if there are any options in the shebang line that I didn't get already when I was exec'ed... (figures out the options; compiles and runs the program).

    Since tilde, alias, and other expansions are done by the shell, they don't work on the shebang line.

Re: #! -- why doth thou exist?
by herveus (Prior) on Aug 25, 2005 at 13:48 UTC
    Howdy!

    The #! line is a general mechanism for an executable script to name its interpreter to the system. Perl does look at it and will respect flags on the line, even if you execute your script via "perl myscript".

    However, the part where it specifies the path to perl only has effect when the script is executed directly as in "myscript".

    Your mileage may vary on non-unix systems.

    yours,
    Michael
      true, and note:
        s/Your mileage may vary on non-unix systems/Your mileage WILL vary on windows/

        Although you will need a shebang if you are running a perl CGI script under Apache over Windows...

        #!D:\perl\bin\perl.exe -T use strict; use CGI; ...blah...

Re: #! -- why doth thou exist?
by VSarkiss (Monsignor) on Aug 25, 2005 at 14:25 UTC
Re: #! -- why doth thou exist?
by samizdat (Vicar) on Aug 25, 2005 at 14:00 UTC
    Sometimes you get more power from UNIX than you expect, as Tanktalus suggests. The shell can be your best friend, but it can obtusely bite you as well. Programs can be written for many interpreters (including many shells and languages), and you mostly do not want to be required to call the interpreter first; you want to 'execute' the file directly. The two bytes \x23\x21 are called the 'magic number' that signifies that the rest of that line is a path to the proper interpreter when they are the first two bytes of the file. However, a direct command line input is interpreted as though it is "$quoted", but the #! line is not. If the interpreter (perl) is already handling the file, the #! looks like a comment.

    There are many reasons why #! exists. You might wish to use a statically-compiled version of a language, or a 64-bit version, for some things and not for others.

    Ah, the power of source code: You could even compile a Perl that reads the #! and replaces itself with the interpreter specified there! :D
      You could even compile a Perl that reads the #! and replaces itself with the interpreter specified there!

      Indeed, perl does this out of the box.

      $ cat foo.sh #!/bin/sh echo 'Hello, World!' $ perl foo.sh Hello, World!

      perlrun has the details, though I prefer Dominus' take in perliaq.

        But, as perlrun says, that trick doesn't work when the interpreter has "perl" in the name, even if it's a different version. That is,
        $ cat foo.pl #!/usr/bin/perl print "$]\n"; $ ~/bin/perl foo.pl

        will run ~/bin/perl, and not /usr/bin/perl. I think this is good more often than not.

Re: #! -- why doth thou exist?
by fokat (Deacon) on Aug 25, 2005 at 14:21 UTC

    Dear punkish

    I'm happily writing this from my PowerBook running Mac OS X. I am totally happy thanks to the following incantation...

    $ su - Password: # cd /usr/bin # mv perl perl-macosx # ln -s /my/new/nice/perl # ^D

    Also, I never download binaries of perl. I rather compile my own. You can use either Fink or Darwin Ports to help with this.

    Best regards

    -lem, but some call me fokat

      $ su - Password: # cd /usr/bin # mv perl perl-macosx # ln -s /my/new/nice/perl # ^D

      This does not seem, to me, the right way to do things. You are replacing the factory-installed perl with your new/nice/perl. If any system level perl-based task expects something in its perl, and doesn't find it in your perl then there could be trouble.

      However, that you don't trust marketplace binaries and roll your own instead is a very worthy sentiment. For now, I am trusting Activestate as a reliable starting point for my own excursions.

      --

      when small people start casting long shadows, it is time to go to bed
Re: #! -- why doth thou exist?
by Nkuvu (Priest) on Aug 25, 2005 at 18:00 UTC
    In addition to the above replies, you can also set your path such that the first perl to be found is the AS perl you installed. In your .cshrc/.tcshrc/.bashrc prepend the path to ~/bin instead of appending it.

    Specifically, in bash it would look like:
    export PATH="/Users/punkish/bin:$PATH"

    So perl somescript.pl will call the AS perl, as it is the one found first. (This last line included in accordance with standards set forth by the Department of Redundancy Department. Oy.)

Re: #! -- wherefore exist thou?
by radiantmatrix (Parson) on Aug 26, 2005 at 16:08 UTC

    The point of #! is to instruct the system which intepreter to start for the script contained below it. If you've already started an interpreter (via calling perl on the command line), the #! is just a comment.

    Perl is courteous, though, so even when it's not being called via #!, the interpreter will check the command-line options on that line and attempt to respect them. For example, using #!/usr/bin/perl -w will turn warnings on even when you launch your script like perl script.pl.

    Shell expansion isn't done on the shebang line by design: the spec for that mechanism demands a real path for various reasons.

    <-radiant.matrix->
    Larry Wall is Yoda: there is no try{} (ok, except in Perl6; way to ruin a joke, Larry! ;P)
    The Code that can be seen is not the true Code
    "In any sufficiently large group of people, most are idiots" - Kaa's Law