How does open 0; print <0>; turn every Perl program into a quine? A. Sinan Unur October 09, 2014

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__ #perltrick — PerlTricks (@PerlTricks) September 19, 2014

I chirped in to point out that neither the while nor the for is necessary as the arguments to print print are evaluated in list context, therefore automatically slurping the contents of the bareword filehandle 0 , and printing them:

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:

If EXPR is omitted, the global (package) scalar variable of the same name as the FILEHANDLE contains 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.

So, when perl sees 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

Another example:

$ 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

Ouch!