56

Which of these is better or faster to use as the shebang line for a Perl script?

#! perl

#! perl.exe

#! fullpath/perl(/perl.exe)

#! partialpath/perl(/perl.exe)

And, when using #!perl, when it works on a particular system, how do I find out in the script which perl interpreter I'm using so I can put that one into the shebang line?


And, if using a /path/path/perl, are * or ... allowed to be used for the folders?

Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
Anonymous
  • 561
  • 1
  • 4
  • 3

8 Answers8

77

If you have to hard code #!, use #!/usr/bin/env perl. Why? What you want is for the Perl program to run with the user's preferred Perl. That's going to be the first on in their PATH. #!perl doesn't do what I mean, it doesn't search the user's PATH, #!/usr/bin/env perl is how you pull that off. /usr/bin/env will always be there on Unix systems.

If the user is using Windows, as others have pointed out, it doesn't matter. Windows doesn't use #! it uses file extension associations. Make sure your program is called foo.pl or something and it'll work. But include the #! line anyway as some utilities and editors make use of it.

If you're shipping code, let the installer take care of it. Both MakeMaker/Makefile.PL and Module::Build/Build.PL will change your #! line to match the perl the user used to install with. They will take care of this problem for you.

If you are installing code for your own production use, you should use the full path to a particular copy of perl. Which copy of perl? One specific to your project. Does this mean you need to compile perl for every project? No, you can make a symlink. Project foo might have /usr/local/bin/fooperl point at /usr/bin/perl5.18. Use #!/usr/local/bin/fooperl. Now if you decide to upgrade perl you can do it per project by changing the symlink.

Schwern
  • 153,029
  • 25
  • 195
  • 336
  • 7
    On Unix, `#!/usr/bin/env perl` may cause a problem if there is more than one version of Perl on a computer. For example, a user account has `PATH` set to have another Perl ahead of `/usr/bin/perl`. The user logs in as "root". Then when root tries to run a system script, this actually runs the non-system perl. So system scripts should not use this. –  May 08 '10 at 00:01
  • 13
    Reason #19382 to not ever log in as root. Use `sudo`. ;) – Schwern May 08 '10 at 05:41
  • 1
    @Schwern: Why would `sudo` prevent this problem? The same thing would happen. –  May 08 '10 at 05:54
  • @jrockway There's a certain point where there's only so much madness you can be expected to deal with. The list of systems which don't have /usr/bin/env is vanishingly small (http://www.in-ulm.de/~mascheck/various/shebang/#env) and if you're the poor admin of such a beast have hopefully symlinked /bin/env to /usr/bin/env – Schwern May 08 '10 at 06:00
  • @Kinopiko `sudo` retains your environment variables, such as `PATH`, unless you tell it otherwise. Anyhow, I agree that system scripts should have their paths hard coded. – Schwern May 08 '10 at 06:06
  • 3
    @Schwern - you forgot one thing - not all user's preferred `perl` binaries are named `perl` :( [ ours is perl5.8 ] – DVK May 08 '10 at 10:13
  • @DVK I didn't forget it, there's just little to be done about it. You've got to pick something, and perl is the most likely to work in the most places. How about symlinking perl5.8 to perl? – Schwern May 09 '10 at 03:02
  • @Schwern - in our case, 2 distinct versions of Perl are in use so no one right version to symlink to :( – DVK May 09 '10 at 04:45
  • 1
    @DVK Perl is backwards compatible, link to the latest one; it will have the best chance of running J Random Perl Script. – Schwern May 10 '10 at 06:16
  • @Schwern - Next time I'm root across 1000s of Unix servers, i'll keep that under consideration... but I'm just a developer with the root access of a caterpillar (sorry, that was a poor pun on real programmers and butterflies :) )... seriously, IIRC there were SOME incompatibilities between 5.005 and 5.8 but it's been a while since I remembered what they were. I can double check if you wish. – DVK May 10 '10 at 10:31
  • 1
    @Schwern, BTW, there's another problem with your suggestion in theory - newer Perl may not have been compiled with backwards-compatible @INC and thus not see every library other Perl does. Our newer Perl doesn't suffer from that issue in practice, but that's due to better than average foresight :) – DVK May 10 '10 at 10:33
  • 6
    @DVK You're right, there are minor incompatibilities, and we could nit pick them all day. Now, which is better: not having anything called "perl" in your path and having no chance of running scripts looking for "perl", and having something called "perl" in your path (you don't need to be root to put a perl symlink in your path) and having a good chance? – Schwern May 12 '10 at 05:50
  • 1
    @Schwern - I think we are thinking in different modes to some extent. I'm thinking global corporate production deployments... you seem more angling for someone's own Unix/Linux environment... in the latter case I'd agree with you, in the former case it's way too un-producton-like if you will, IMHO... – DVK May 12 '10 at 08:56
  • Some Linux versions put perl in /usr/bin instead of /usr/bin/env – Jim2B Oct 28 '15 at 16:11
  • 3
    @Jim2B Yes, nearly *all* Unixes put perl in `/usr/bin`. [`/usr/bin/env`](https://en.wikipedia.org/wiki/Env) is not a directory, it is a program. `#!/usr/bin/env interpreter` is a common way to launch an interpreter without using a hard coded path. – Schwern Oct 28 '15 at 17:17
  • OpenSSL's [Configure](https://github.com/openssl/openssl/blob/master/Configure) is a Perl script *without* a shebang or extension. If you [set/reset execute permissions as customarily expected](https://unix.stackexchange.com/questions/293524/properly-set-execute-bit-based-on-file-type), then trying to run it results in ***`./Configure: Permission denied`*** because it does not get the execute bit. – jww Jul 10 '16 at 05:36
  • @jww There is a shebang line [right in the file you listed](https://github.com/openssl/openssl/blob/master/Configure#L1) and it is `#! /usr/bin/env perl`. [It was added Nov 2015](https://github.com/openssl/openssl/commit/de17db915e26452819692fd837d788d52b8dd48a). It replaced a technique designed to support extremely old and incompatible shells. Those shells would ignore a shebang and execute the file as a shell script. As for resetting permissions, `file` understands `#!/usr/bin/env perl` fine. – Schwern Jul 10 '16 at 05:44
  • 1
    Oh, my bad. I linked to OpenSSL's `Configure`, but I cat'd [the `Configure` Microsoft provides at their fork](http://github.com/Microsoft/openssl/blob/WinRT/Configure). Of course, the MS one is missing the shebang... Sorry about that. – jww Jul 10 '16 at 05:48
  • @Schwern: for the EUMM/MB case scripts currently should *not* have `#!/usr/bin/env perl` as the shebang, but rather just `#!perl` or `#!/usr/bin/perl`. See https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/issues/58 – Slaven Rezic Dec 13 '18 at 22:14
  • @SlavenRezic Yes, EUMM/MB are correct to not use `#!/usr/bin/env`. This was [a hard coded shbang specific to an OpenSSL script](https://github.com/openssl/openssl/blob/master/Configure). – Schwern Dec 13 '18 at 22:34
  • Alas, the `env` trick won't work if you're trying to replace a shebang line that has command line arguments, e.g. `#!/usr/bin/perl -w` can't be replaced by `#!/usr/bin/env perl -w` because the kernel will pass `perl -w` as a single string to `env` and you'll get `env: perl -w: No such file or directory` – Ian D. Allen Mar 05 '20 at 17:10
  • 1
    @IanD.Allen Works For Me™ with both BSD and Gnu env. You can also use `env -S` to tell it to split its arguments, Perl is even the example used. Perl also has its own #! processing, see perlrun. If it doesn't work for you, many command line switches can be emulated in code such as `BEGIN { $^W = 1 }`. – Schwern Mar 05 '20 at 19:03
  • @Schwern I use `env` on Linux Ubuntu 18.04 LTS that has `coreutils 8.28` and there is no `-S` option. The Linux kernel doesn't split shebang arguments on blanks, though it does remove leading and trailing blanks. – Ian D. Allen Mar 06 '20 at 20:57
  • 1
    @IanD.Allen You are correct! -S appears to have been added in coreutils 8.30. Not sure how long BSD has had it. So yes, command line arguments are not safe with /usr/bin/env. You'll have to use their code equivalents. – Schwern Mar 06 '20 at 21:50
  • env doesn't allow you to put arguments on the line with your perl. Is there a portable way to do something like: "env perl -T -w" ? – Astara Oct 25 '20 at 23:50
  • @Astara Most command line options have code equivalents, see [perlrun](https://perldoc.perl.org/perlrun#Command-Switches). `-T` is a special case, it must be on the command line. Both are clumsy hammers with global effects, in particular many modules are not taint clean. Instead of `-w`, consider `use warnings` instead. If you must have portable taint mode, a small wrapper that sets `PERL5OPT='-T'` before executing the program will do. – Schwern Oct 26 '20 at 00:06
  • Not my code -- spamassassin puts -T & -w on their command lines with hard coded version and location of perl. Except that I perl can be updated apart from spamassin -- should be upgradeable from 5.28.0->5.28.1..2, 3..etc. also location can change as well. It's always better to use the user's path set up by the machine admin. It's considered bad form to hard code constants like pathnames in your program. it makes them frail. And people wonder why SW qual is going down .. programs are more and more designed to fail. – Astara Oct 29 '20 at 20:21
  • @Astara SpamAssassin is doing the right thing, Perl programs need to use the same Perl as their supporting modules are installed in. `#!/usr/bin/env perl` could find a Perl that doesn't have Mail::SpamAssassin installed, or has an incompatible version. [Upgrading Perl can be managed using perlbrew](https://perlbrew.pl/Reinstall-All-Modules-On-New-Perl.html). – Schwern Oct 29 '20 at 20:56
  • SA uses the exact address for their pure perl version. For their COMPILED version, which might have more need for binary compatibily, does NOT use the absolute perl path but hard-coded directories only differing by the Perl-lang-ver(5) and perl5's Major-ver, so 5.012, 5.014...5.030. The perl-only version is less likely to fail unless they've used newer lang features, where you need to include a "use 5.10" to activate. They can't be doing "the right" thing by doing 2 different things. I recommend: perl-only, use 'use 5.x'. Bins -- rebuild for perl you are using. – Astara Oct 30 '20 at 23:00
  • @Astara "*SA uses the exact address for their pure perl version.*" Yes, that is the normal behavior for Perl programs and is handled by the Perl build system. I can't speak to what their C binary does. I agree that some projects get it wrong. If you have an issue with SpamAssassin, you should [raise an issue with them](http://bugzilla.spamassassin.org/). – Schwern Oct 30 '20 at 23:09
  • Hard coding the location of the interpreter overrides local system policy about how perl is used and installed. Also, perl developers claim that the API will only change between major versions (5.24->5.26), so the module installer, by making modules specific to 5.24.[0..6] or however many bug fix releases are done. Forces installations to give up perl-updates unless all of the modules are updated/reinstalled. This is bad enough between major versions, but entirely unsupportable for minor fixes which are not to change the API. – Astara Oct 31 '20 at 21:43
  • @Astara This is well off-topic. Perl installation policy is restricted by some technical realities. I used to maintain that system. If you'd like to discuss it I've made a chat room. https://chat.stackoverflow.com/rooms/223923/chat-about-perl-installation-policies – Schwern Oct 31 '20 at 21:58
  • @Astara [I'm happy to discuss this in chat](https://chat.stackoverflow.com/rooms/223923/chat-about-perl-installation-policies). – Schwern Nov 02 '20 at 21:58
  • Your answer gives contradictory advice. You say to use the perl installer which hard codes the interpreter path, but in the next paragraph say to use a symlink for the interpreter so you can update it to point to the desired version of perl. The problem is the installer overrides the use of the symlink by reading the symlink and hard coding the absolute path without allowing any redirection. You say what the installer is correct, but if that's true, then why say to use a symlink (which, BTW, is what I did)? – Astara Nov 02 '20 at 22:21
  • @Astara A stand-alone script that will run on any reasonably recent version of perl should use `#!/usr/bin/env perl`. You don't need an installer, it's just a single file like a shell script. That means only core modules, only stable features, and tolerance of old bugs. An application which relies on 3rd party modules, like SpamAssassin, *must* be tied to the same perl which has those modules installed. Keep in mind this answer is 10 years old, perlbrew barely existed, and is not a complete guide. If you'd like to help update it, please join me in chat. I will not answer further comments. – Schwern Nov 02 '20 at 23:12
8

If you are running CGI via Apache on Windows, the SHEBANG IS USED. You will need the fullpath to perl.

user2509628
  • 106
  • 1
  • 1
8

A Windows she-bang (deduced from the perl.exe bit) seems irrelevant since your (ahem) "shell" probably does not even parse it (correct me if I am wrong, could have been changed lately).

Some command line flags may still be picked up by Perl itself though (according to this thread).

Dodgie
  • 643
  • 1
  • 10
  • 17
ChristopheD
  • 112,638
  • 29
  • 165
  • 179
6
  1. As ChristopheD noted, I can confirm from practice (ActivePerl on XP) that the shebang line is not really necessary on Windows.

    A shebang line tells a Unix shell which interpreter to pass the script to.

    On Windows, the program to pass the script to will be determined by associations based on the extension.

  2. On Unix, the third option (full path to perl executable) is best.

    And yes, you can use ".." in theory (shell doesn't care) but you should not really use relative path - you never know what your current working directory when executing a script will be.

DVK
  • 126,886
  • 32
  • 213
  • 327
5

If you're developing in Unix using Perl and you use "perlbrew" to easily switch between different versions of Perl, then the "#!/usr/bin/env perl" shebang line works well.

I originally had the first 2 characters in the shebang line reversed. Just fixed/edited that.

Community
  • 1
  • 1
  • You have the `!#` backwards in your `!#/usr/bin/env` above. Shebang lines always begin with `#!` because `#` is a comment line to the shell. – Ian D. Allen Mar 05 '20 at 16:53
  • I just found out you can't use arguments with perl like that. I.e. someone wanted to have -T -w on their taint, but that won't work with /usr/bin/env...annoying. – Astara Oct 25 '20 at 23:47
4

The first line stands for shebang. It basically tells the program where Perl interpreter is located since Perl is interpreted language. On Linux you can type in terminal:

whereis perl

which will give you exact location of it. Usually it's inside /usr/bin/perl. This means that you want to make shebang regarding to /usr/bin/perl

#! /usr/bin/perl

use strict;
use warnings;
use v5.10.1;
.
.
.

This is just some good practice, hence it's obviously fastest solution.

I hope you find this useful,

Thanks.

miksiii
  • 2,426
  • 26
  • 22
1

And, when using "#! perl", when it works on a particular system, what is the print() for showing the full path to perl.exe, that could be included into the Shebang Line ?

Well, if you're using the print statement you are already executing perl code, so...

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
0

This is one of the things which I dislike about Perl.

On Windows, if you are using ActiveState Perl at least, if the file ends with .pl then the Windows registry will run the Perl interpreter for you, regardless of the shebang line. On Cygwin, I am not sure why but #! perl works too. On Unix you should put the full path to your Perl executable in the shebang line. Schwern's idea of using env is convenient, but has some danger, as I pointed out in a comment.

This is why I suggest to you that the best solution is to package your Perl scripts as CPAN modules. CPAN installers like Module::Build will then change the shebang line to the full path to your Perl interpreter. (I am not sure whether Schwern's installer, ExtUtils::MakeMaker, does this or uses env, since I don't use it.)

Community
  • 1
  • 1
  • 2
    The Module::Build #! fixup code came from MakeMaker which came from the pink Camel book. They all hard code the path to perl. – Schwern May 08 '10 at 05:51
  • Yeah I noticed this in spamassassin, their first line shows: "#!/home/perl/perl-5.28.1/bin/perl -T -w. I have a symlink at /usr/bin/perl pointing to my perl installation. I use that to have a version-non-specific path to use perl, AND when I want to test different versions, I add the bin dir of the perl I want to test to the front of my path. Works great for things that don't hardcode paths. – Astara Oct 25 '20 at 23:55
  • Also, that means a bunch of scripts will stop working if I upgrade my perl -- binaries I can understand and update through CPAN, but much of perl is architecture independent, and at the very least, perl claims to hold their API fixed in the major release (5.28.{0,1,2,3...}. Hard coding dependencies is like hard coding your code to break when libraries are added. Windows solved this by keeping multi versions of libs for different version progs, Even Unix solved it with versioned so's like perl-5.6.6.so and perl-5.16.3.so could boths be in the lib and progs link to 5.6 or 5.16 depending on need – Astara Oct 29 '20 at 20:17