I know this is incorrect. I just want to know how perl parses this.
So, I’m playing around with perl, what I wanted was perl -ne what I typed was perl -ie the behavior was kind of interesting, and I’d like to know what happened.
$ echo 1 | perl -ie'next unless /g/i'
So perl Aborted (core dumped) on that. Reading perl --help I see -i takes an extension for backups.
-i[extension] edit <> files in place (makes backup if extension supplied)
For those that don’t know -e is just eval. So I’m thinking one of three things could have happened either it was parsed as
perl -i -e'next unless /g/i'i gets undef, the rest goes as argument to eperl -ie 'next unless /g/i'i gets the argument e, the rest is hanging like a file nameperl -i"-e'next unless /g/i'"whole thing as an argument to i
When I run
$ echo 1 | perl -i -e'next unless /g/i'
The program doesn’t abort. This leads me to believe that 'next unless /g/i' is not being parsed as a literal argument to -e. Unambiguously the above would be parsed that way and it has a different result.
So what is it? Well playing around with a little more, I got
$ echo 1 | perl -ie'foo bar'
Unrecognized switch: -bar (-h will show valid options).
$ echo 1 | perl -ie'foo w w w'
... works fine guess it reads it as `perl -ie'foo' -w -w -w`
Playing around with the above, I try this…
$ echo 1 | perl -ie'foo e eval q[warn "bar"]'
bar at (eval 1) line 1.
Now I’m really confused.. So how is Perl parsing this? Lastly, it seems you can actually get a Perl eval command from within just -i. Does this have security implications?
$ perl -i'foo e eval "warn q[bar]" '
Quick answer
Shell quote-processing is collapsing and concatenating what it thinks is all one argument. Your invocation is equivalent to
It aborts immediately because perl parses this argument as containing
-u, which triggers a core dump where execution of your code would begin. This is an old feature that was once used for creating pseudo-executables, but it is vestigial in nature these days.What appears to be a call to
evalis the misparse of-e 'ss /g/i'.First clue
B::Deparse can your friend, provided you happen to be running on a system without
dumpsupport.So why does
unledisappear? If you’re running Linux, you may not have even gotten as far as I did. The output above is from Perl on Cygwin, and the error aboutdumpbeing unsupported is a clue.Next clue
Of note from the perlrun documentation:
Working hypothesis and confirmation
Perl’s argument processing sees the entire chunk as a single cluster of options because it begins with a dash. The
-ioption consumes the next word (enext), as we can see in the implementation for-iprocessing.For the backup file’s extension, the code above from perl.c consumes up to the first whitespace character or end-of-string, whichever is first. If characters remain, the first must be whitespace, then skip it, and if the next is a dash then skip it also. In Perl, you might write this logic as
Then, all of
-u,-n,-l, and-eare valid Perl options, so argument processing eats them and leaves the nonsensicalas the argument to
-e, which perl parses as a series of divisions. But before execution can even begin, the archaic-ucauses perl to dump core.Unintended behavior
An even stranger bit is if you put two spaces between
nextandunlessthe program attempts to run. Back in the main option-processing loop we see
The extra space terminates option parsing for that argument. Witness:
but without the extra space we see
With an extra space and dash, however,
Design motivation
As the comments indicate, the logic is there for the sake of harsh shebang (
#!) line constraints, which perl does its best to work around.