in reply to synopsis=>warn
@ARGV = ${$-=$.}, s<#<>q#>#q<<>> #exegesis=>print, hacker=>unless $/=q=echo q/Just another Perl /| $/=!~40.46.42.41#apocalypse=>die
While looking at the 4 lines you just can recognize some words and operators which gives its own interpretation of how the job is done:
Exegesis print hacker unless echo /Just another Perl/ | apocalypse => die
In some programing languages the | stands for or and in math => is used to indicate an implication.
However all this gives no clue of how it works. Look upon from a Perl programmer point of view, one will recognize the first statement @ARGV which is by definition a list object. It is followed by an equal sign and some garbage joined by comma and long comma. But that is all you can say due to you can’t really say where that list ends if it does.
Even with some intermediate Perl knowledge you can’t say much more as that the @ARGV object is a special Perl variable as they are frequently used in japhs to shorten the code and at the same time confuse the reader.
Transformierung code
To understand what’s going on, we can try to remove the uncertainties for the reader and rewrite the code in a way that it shows explicit what the interpreter does. Always under the strict permission that the code still runs as before.
The first thing to do is to explicitly try to find statements and blocks. By playing with inserting do{} block in front of the unless statement and replace comma with semicolon, where ever statements end. We come to something like this code:
do{ @ARGV = ${$-=$.}; s<#<>q#>#q<<>>#exegesis; print; hacker; } unless ( $/ = (q=echo q/Just another Perl /| $/=) !~ 40.46.42.41 ); #apocalypse=>die
This doesn’t give much clue about how it works, but now we can see some unnecessary code, which we can remove.
The word exegesis in replacement statement s<#<>q#>#q<<>>#exegesis is nothing but some search modifier. Not all of these modifier letters are necessary. And after cleaning the separators and pattern up, it simplify to: s//<>/ee.
Another mythic line includes the sequence 40.46.42.41 which turns out to be the ASCII-code representation of the string (.*) adding some separators slashes the match pattern can be written as m/(.*)/. In the same line we can replace the equal signs q= ... = used as separators with some ticks ' ... '.
Due to the fact that the unless can be written as if not and (not !~) is =~. And the search pattern .* matches almost everything so the condition in the if statement is always true. We use this fact to remove that if completely and put the code in linear order. Leaving out comments the code transforms in:
$/= ('echo q/Just another Perl /| $/' =~ m/(.*)/); @ARGV = ${$- = $.}; $_ =~ s//<>/ee; print; hacker;
Now we removed almost all, only the $- special variable is still obsolete in the line @ARGV = ${$- = $.}. If you put the space somewhere else, for example like this @ARGV = ${$ -= $.} you can imagine important is only $. which is the current line number for the last file handle accessed.
To see witch value is in $., we need to use some debugging tools. I prefer the print statement. However this is impossible due to the fact that the behavior of the script changes depending on the used output pipe and output produced. To anticipate this problem, we can separate the reading and evaluation in the replace statement and add the debug print in between like this:
$/= ('echo q/Just another Perl /| $/' =~ m/(.*)/); @ARGV = $b = ${$- = $.}; #$_ =~ s//<>/ee; $a =<>; print "\n" . "v" x 20 . " -> \$-=${-} : \$${-}=". $b ."\n$a\n" ."^" x 20 ."\n"; $_= eval "$a"; print "$_"; qq'hacker';
Running this script (MSWin32) gives:
C:\japh_debug.pl vvvvvvvvvvvvvvvvvvvv -> $-=0 : $0=C:\japh_debug.pl $/= ('echo q/Just another Perl /| $/' =~ m/(.*)/); @ARGV = $b = ${$- = $.}; #$_ =~ s//<>/ee; $a =<>; print "\n" . "v" x 20 . " -> \$-=${-} : \$${-}=". $b ."\n$a\n" ."^" x 20 ."\n"; $_= eval "$a"; print "$_"; qq'hacker'; ^^^^^^^^^^^^^^^^^^^^ vvvvvvvvvvvvvvvvvvvv -> $-=1 : $1=echo q/Just another Perl /| q/Just another Perl / ^^^^^^^^^^^^^^^^^^^^ Just another Perl hacker
This gives some insight. First we can see that our extra print gives 2 blocks. This means, that our debug print statement was called 2 times! The first block includes the complete script file contents. Due to the fact that this block is evaluated it is clear why the print is executed a second time. Due to the fact it was called only 2 times and not more, it follows that something has changed in between of the calls. The only dependency is $., it turns from 0 to 1.
We can now imagine ${$- = $.} is treated as ${”$.”} which collapses to $0 for $.==0 holding the program name, while for $.==1 is the match result $1. This match result is 'echo q/Just another Perl /|' as such it is at the same time a valid executable command line, when run returning Perl code string "q/Just another Perl /". Because of the pipe | symbol Perls open function involved interprets the "filename" in $ARGV[0] 'echo q/Just another Perl /|' as a command and its output is piped and read in again to the star operator <> as string 'q/Just another Perl /.
Summing up the execution of the eval statement prints the string "Just another Perl " and returns the word "hacker" to be printed immediately after that. The word "hacker" is returned due to the fact that it is the last statement in the eval block. This is true even when warped in the unless().
That’s why you see finally written "Just another Perl hacker".
For me it appears that when there is a japh camel become like dogs hunting for a stick. Some hunt even longer than an hour, so for these I hope this is a pleasant short cut :-)
Have a lot of fun
Michael
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: synopsis=>warn
by Grimy (Pilgrim) on Sep 11, 2014 at 13:52 UTC |