The other day, on the heels of a brief exchange of tweets:
Make a Perl program print itself:
seek(DATA,0,0); print while (<DATA>); __DATA__
— PerlTricks (@PerlTricks) September 19, 2014
open 0; print while <0>;
— Rafaël Garcia-Suarez (@consttype) September 19, 2014
open 0;print for<0>;
— Tux (H.Merijn Brand) (@Tux5) September 19, 2014
I chirped in to point out that neither the
while nor the
for is necessary as the arguments to
0, and printing them:
open 0; print <0>;
— A. Sinan Unur (@sinan_unur) October 2, 2014
But, why is
open 0; equivalent to opening the source of the script that is running?
You probably do know that the special variable
$0 holds the name of the program that is being executed. It is not universally guaranteed (see
perldoc -v '$0'), but this will usually be a string you can pass to
open to open the source of your script.
But, how does
open 0 end up opening this file?
To my dismay, I found that
perldoc -f open in most recent versions of Perl don’t have this, but versions as recent as
5.18.2 explain what happens when
open is invoked with a single argument:
EXPRis omitted, the global (package) scalar variable of the same name as the
FILEHANDLEcontains the filename.
Clearly, I don’t recommend relying on this: If nothing else, you should avoid using global variables, and you should use the three argument form of
open anyway. I am just explaining how this trick works.
open 0;, it does the equivalent of
open 0, '<', $0.
You can easily verify this:
$ cat 0.pl #!/usr/bin/env perl # We are not golfing any more use autodie; use strict; use warnings; $0 = 'does not exist'; # Thanks Peter open 0; $ ./0.pl Can't open('0'): No such file or directory at ./0.pl line 9
$ cat evil.pl #!/usr/bin/env perl 'does not exist.txt' =~ /\A(.+)\z/; open 1; print <1>; $ cat 'does not exist.txt' it does exist -- Dr. Evil $ ./evil.pl it does exist -- Dr. Evil