http://qs321.pair.com?node_id=1154173

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

Hello monks,

Foreword During lasts weeks seems I was very active in producing oneliners (so much that I'm tempted to write some tutorial about some useful teqniques).

In one oneliner where i was fixed for a parametrizable solution i come across the -s perl's switch, that i admit I was completely unaware of.

In perlrun few lines are dedicated to it. It is somtehing difficult to search informantions for, but I found:

From what i understand from official docs it works on the shebang line: it must also run from command line for oneliners and other programs too.

Let's see what I tested given simple.pl program as follow:

# use strict; # UPDATE: that was commented as spotted by Eily +( see below) # use warnings; # UPDATE BEGIN{print "inside BEGIN \@ARGV is [@ARGV]\n"} my $test='original value'; print "inside main \@ARGV is [@ARGV] and \$test is [$test] +\n";

perl -s simple.pl -test=SET_VIA_-s arg1 inside BEGIN @ARGV is [arg1] and $test is [SET_VIA_-s] inside main @ARGV is [arg1] and $test is [original value]

Ie $test is set by the commandline switch -test=SET_VIA_-s and is visible in the BEGIN then the body of the program gives it another value original value Why this does not deparse to anything visible (as opposite of other switches like -l -n -p -a -F )?

perl -MO=Deparse -s simple.pl -test=SET_VIA_-s arg1 inside BEGIN @ARGV is [arg1] and $test is [SET_VIA_-s] sub BEGIN { print "inside BEGIN \@ARGV is [@ARGV] and \$test is [$test]\n"; } my $test = 'original value'; print "inside main \@ARGV is [@ARGV] and \$test is [$test]\n"; simple.pl syntax OK

while in the oneliner version (without strict and warnings)

perl -se "BEGIN{print qq(inside BEGIN \@ARGV is [@ARGV]\n)};print + qq(inside main \@ARGV is [@ARGV] and \$test is [$test]\n);" -test=SET_VIA_-s arg1 inside BEGIN @ARGV is [arg1] Can't modify constant item in scalar assignment at -e line 2, near + "SET_VIA_-s" syntax error at -e line 2, near "SET_VIA_-s" Execution of -e aborted due to compilation errors.
And using the -- termintation of switch processing it works fine:
perl -se "BEGIN{print qq(inside BEGIN \@ARGV is [@ARGV]\n)};print + qq(inside main \@ARGV is [@ARGV] and \$test is [$test]\n);" -- -test=SET_VIA_-s arg1 inside BEGIN @ARGV is [arg1] inside main @ARGV is [arg1] and $test is [SET_VIA_-s]

But adding strict and warnigs and the my declaration for $test (as in simple.pl ) the oneliners version gives different results:

perl -se "use strict; use warnings;BEGIN{print qq(inside BEGIN \@ +ARGV is [@ARGV]\n)}my $test='originalvalue';print qq(inside main \@ +ARGV is [@ARGV] and \$test is [$test]\n);" -- -test=SET_VIA_-s arg1 inside BEGIN @ARGV is [arg1] inside main @ARGV is [arg1] and $test is [original value]

In addition the evil behaviour explained in the above mentioned thread is still active, and evem more incomprensible if you add a qq(..)

perl -se "'A'=~/(A)/;print $1 " -- -1=OUCH! OUCH! perl -se "'A'=~/(A)/;print qq($1\n)" -- -1=OUCH! A

personal conclusions about -s switch

It is said in perlrun that enables rudimentary switches. It is not too reductive word?. Is not worth to spend some word more in the official docs, explaining that MUST be used only in oneliners to act as rudimentary switch's processor (only oneliners examples, not short script)? Are my conclusions correct? Cannot be that switch a candidate to be removed? Why it's usage does not deparse to something visible? what the hell in the last example?

L*

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Replies are listed 'Best First'.
Re: about perl -s switch -- usable? evil? unneeded?
by Eily (Monsignor) on Feb 01, 2016 at 13:05 UTC

    Your first output doesn't match your first program, since the variable $test is not printed in the BEGIN block. I suppose this is because you couldn't compile with strict, the solution to that is to declare the variable with our (which will just alias $test to $main::test). Having lexicals override package variables, and our variables (locally aliased? I can't remember if there's a standard name for those) is true even without the -s switch. Actually the $test in the BEGIN block and the $test after the my declaration are two different variables that happen to have the same name. Without strict, the fact that a -s variable is a package global can be implicit.

    On the main subject now, on whether -s should be used/kept: I like that perl allows unsafe but useful features that you can use for oneliners and other throwaway code. So having an option with some caveats is OK for me, I just try to avoid them when I'm not writing in a console. The thing is, having a "rudimentary switch" mechanism for any kind of program means that you intend to use it several times, or even that you may not be the only one to use it. For me this is not compatible with the shortcomings of -s, so I would never use it. But I like how perl's philosophy is to "give the user enough rope to hang themselves" but tell them how to avoid the pitfalls, rather than try to secure everything and remove the need for a better understanding. So remove -s, why not? But since it is little known option, and it does have its advantages when used correctly, I don't think it's that much of a hazard (unlike <> or the two parameters open, which are not only really common, but also more standard).

      Thanks for spotting my error; maybe i've done too much test and i become mazed. i've put a comment in the above code pointing to your precious answer.

      I'm with you in your second paragraph too. I have not fear of (Perl's) dangerous things (and if you search for mine usage of eval string you can say i hazard..) but i also like to know when something is flammable. The last test (ovverding $1 above) was chocking for me. I'd like at least be adviced by the perlrun man page.

      More: the -s inanity respect variables declared with my and the few words dedicated to it let me think of some vestige from the past. Imagine if -s had the ability to modify lexical variables in the main package just after their first declaration: with this ipothetic functionality you would be able to ovveride some default value to test your program in seconds, from command line. Like a totally new environment.

      If I remember correctly -s is in the default shebang of some valuable monk here around.

      Many question are still open for me as why it not deparse to nothing and why the last behaviour ovverriding or not a readonly variable depending on the qq()

      At the end I confess i found not enough information to have my curiosity satisfied and i hoped this post could get some interesting contribution from them who know more.

      thanks again for your keen sight and your opinion.

      L*

      There are no rules, there are no thumbs..
      Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: about perl -s switch -- usable? evil? unneeded?
by mr_mischief (Monsignor) on Feb 01, 2016 at 18:27 UTC

    If you want an answer that like a one-liner is short, dirty, simple, and to the point: if you want things clean and maintainable don't write them as one-liners.

    There is Getopt::Long if you want a clean, maintainable options mechanism. You can, although it's generally not very advisable, roll your own complex @ARGV handling. You could write some quite simple @ARGV handling, but the -s switch does that much for you. So use -s where you want very simple argument handling for a quick and dirty solution like a one-liner, and use a well-understood and widely used option handling mechanism like Getopt::Long when you are writing something to be reused and maintained.