The first line of Perl_CGI script, env perl vs perl only, how different?

Hi ! Everyone there ! How are you ?

Until recently I runs all of my Perl scripts as well as Perl_CGI scripts by starting the folowing salutation,

#! /usr/bin/perl -w

The script with this beginning runs well at BASH shell at (/home/mkido/bin) LINUX such as Fedora, Ubuntu, Rocky (Alma-derivative). However, almost right now I noticed some of Perl example around has the different first line as below,

#! /usr/bin/env perl

And it doesn't seem to run at HOME BASH shell (/home/mkido/bin) by simple way of executing it by-itself by the command line. Will someone explain me about what is this [env perl] stuff? Thank you so much.

Mitsuru Kido

6 Comments

The difference doesn't have anything to do with Perl; it's how unix-like operating systems interpret files that start with a shebang (#!).

The first part after the shebang is the pathname to the executable that will be called with the file as the argument. If your file starts with

#!/usr/bin/perl
then the OS will execute the /usr/bin/perl file and hand it your script... assuming there's a /usr/bin/perl file to execute (usually there is). It's the exact equivalent to typing /usr/bin/perl yourscript.pl at your command line.

However, if your script starts with

#!/usr/bin/env perl
the OS will execute the /usr/bin/env file and hand it your script. How is this different? Well, the difference is that /usr/bin/env looks at the rest of the first line and it searches for the command in your path. Let's say you have /usr/bin/perl, but it's a crappy perl 5.10 that was installed by your operating system, and you have perl 5.36 installed at /usr/local/bin/perl. Putting /usr/local/bin in your path earlier than /usr/bin isn't going to do any good if your scripts all start with
#!/usr/bin/perl
(or if you run all your scripts from the command line with /usr/bin/perl yourscript.pl), because those scripts will execute using the crappy 5.10 that's available at /usr/bin/perl. By using #!/usr/bin/env perl, it's the same as invoking the perl yourscript.pl : the OS searches your path and uses the first perl executable it finds, whether that's the one you have installed at /usr/local/bin/perl, or $HOME/perl5/bin/perl, or $HOME/perl5/perlbrew/perls/perl-5.36.0/bin.

You can read more about the env command at https://man7.org/linux/man-pages/man1/env.1.html

Also, the -w you see in the #!/usr/bin/perl -w is just passing the "enable warnings" flag to Perl. If you're using /usr/bin/env, you can do the same thing by putting

#!/usr/bin/env -S perl -w

However, I dislike using command line switches to do things in shebang lines. Command line switches are good for one-liners, but if I'm writing a script anyway, I'm just going to do things in a more verbose, easier to read way. That's why all my perl scripts start with

#!/usr/bin/env perl
use strict;
use warnings;

More info on how to invoke Perl: https://perldoc.perl.org/perlrun

Avoiding doing things on the shebang line is a matter of coding style and therefore subjective.

There is a much more important reason to avoid -w, which is objective: it’s not at all the same thing as use warnings. Whereas use warnings applies to the rest of the current scope, -w is completely global. Under -w, any module loaded directly or indirectly will have warnings forced on it, even if the module itself does not turn on warnings – which nowadays almost certainly means it was written to run without warnings. Therefore -w should no longer be used. At all.

We have had use warnings since Perl 5.6 – in fact lexical warnings were one of the major changes in that version. 5.6 came out in 2000. The -w switch is 1990s technology.

I've also seen this:

#!perl

And it seems to work like "#!/usr/bin/env perl" on Linux (i.e. $PATH is consulted), but it fails completely on macOS. Best avoided.

Leave a comment

About Kido Mitsuru

user-pic To ask questions to this blog community