Xiong has asked for the wisdom of the Perl Monks concerning the following question:
Here's a construct stinking to me of the multiplatform workpla¢e. This is the top of a cpan script newly created (by $ /lab/bin/perl -MCPAN -eshell) for the purpose of downloading modules into my development perl only under Linux:
#!/lab/bin/perl eval 'exec /lab/bin/perl -S $0 ${1+"$@"}' if $running_under_some_shell; #!/usr/bin/perl
... followed by what looks like reasonable Perl code.
Two questions:
1. Practically, can I replace this gubbins with one clean hashbang line?
2. Academically, what exactly is going on here?
perlrun (near -S):
#!/usr/bin/perl eval 'exec /usr/bin/perl -wS $0 ${1+"$@"}' if $running_under_some_shell;
and the even more baroque:
eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}' & eval 'exec /usr/bin/perl -wS $0 $argv:q' if $running_under_some_shell;
Gloss on above from MadMongers is notable for the hints:
Yeah, that's a winx thing... ...the first part of the script is both (ba)sh and perl acceptable...
Something Google sucked into its archives uses a similar deal several times in one file, if i read aright:
sed "s/^X//" >'dbdump' <<'END_OF_FILE' X: #!/usr/bin/perl Xeval 'exec /usr/bin/perl -S $0 ${1+"$@"}' X if $running_under_some_shell; X#!/usr/local/bin/perl
The Camel 24.5.1. Generating Other Languages in Perl (so I guess this is official):
print &q(<<"EOT"); : #!$bin/perl : eval 'exec $bin/perl -S \$0 \${1+"\$@"}' : if \$running_under_some_shell; : EOT
Grokbase startperl insanity:
print OUT <<"!GROK!THIS!"; $Config{startperl} -- # -*- perl -*- eval 'exec $Config{perlpath} -S \$0 \${1+"\$@"}' if \$running_under_some_shell; !GROK!THIS!
This last is noteworthy in that -*- (seen in perlrun) is explained to be not merely a whimsical example but a bonafide workaround for some terrible weirdness:
By the time there's the -*- perl -*- in place, the #! redispatcher code is happy, in that it doesn't attempt to re-exec. Adding another #!perl and an -x earlier doesn't seem to make a difference. Taking out the -*- perl -*- causes an infinite loop
This page also has the charming metasyntactic variable I employ with relish in this post.
Finally, from an older copy of the cpan script on my very own machine:
#!/usr/bin/perl eval 'exec /usr/bin/perl -S $0 ${1+"$@"}' if 0; # not running under some shell
This annoys me thrice. There's something blatant about if 0; the comment seems to invert the test relative to previous examples; this script is generated to run on a Linux box known to interpret hashbangs correctly.
I gather that the test, both here and in other examples, will not execute under most shells but the preceeding eval will; while perl will execute the test and ignore the eval.
I also gather that command-line arguments are being passed through to perl when the shell executes; but then why the 1+? How, in the 21st Century, did this 19th Century springloaded contraption come to spray tiny oily sprockets across my workbench?
My conclusions are: Yes, I can lop off this gubbins and replace it with one honest hashbang; and Blame Micro$oft. Please correct, expand, and illuminate.
Update:
Corion, thank you++ for that detail. Of course this still leaves open the question of why such an obscure approach is required. In a way, it's worse, all in the family. Can't all shell authors agree on one idiom for dispatching scripts?
rubasov, thank you++ for the extremely detailed breakdown. Practically, I don't have to know what this thing does to delete it. It's a curiosity, though; an itch I had to scratch.
One wonders how long a script could be written that would execute (differently but without error) under how many shells and interpreters. Upvote ambrus for a strong effort but I was thinking of something a tad bit more audacious. Topic for another node...
And yes, thank you++ shmem. It's always good to hear the other side of the issue. Complacency is a greater threat to excellence than ignorance.