Ramblings of Narc

When the issue isn't confused enough.

Self-reproducing Programs

Once upon a time, I was surfing the Web more or less randomly, when I came across the concept of a “quine” (probably on this page). I had a look and was suitably impressed — the idea of a program that can print its own source code seems very simple until you try to do it for real, at which point, you quickly abandon all hope of ever really doing it without cheating.

What this misses out on is that most programs like this involve some type of cheating — exactly how, though, is up to the author. The most obvious cheat is to read in the file containing your own source code and print that — but that’s too easy. Not to mention, hey — maybe there is no such file. Then what do you do?

In any case, I abandoned the thought and went back to my normal world of programs that don’t really know themselves… until today. Today I came across this self-recursive story (via archive.org — original website no longer exists) (and I encourage you to read it if you have a strange sense of humor like mine). Following links around that site, I eventually found this reference to “selfish code”, which links back to that quines page I mentioned first.

This time, armed with a bit more patience and a crapload more experience, I was able to decypher the code so much easier, and I could see the little “cheats”, and why they worked. But among all the programs on that page, there was one I didn’t particularly like. It was this one:

$b='$b=%c%s%c;printf$b,39,$b,39;';printf$b,39,$b,39;

It looks nice, and does print itself, but… it doesn’t have the #!/usr/bin/perl at the start, so if you want to execute it, you need to do perl -c source-file or perl -e "[code]". So I figured I could extend it to include the hash-bang, couldn't I?

...

Well, after a number of iterations, I eventually came up with this:

#!/usr/bin/perl

$a="#!/usr/bin/perl";
$b='%c%c$a="%s";%c$b=%c%s%c;%cprintf$a;printf$b,10,10,$a,10,39,$b,39,10,10,10;%c%c';
printf$a;printf$b,10,10,$a,10,39,$b,39,10,10,10;

It successfully reproduces itself, and uses quite a little bit of magic to achieve that.

What's the cheat? We're printing the \n characters using sprintf('%c',10), and the single quotes in a similar way, but with the character code 39. This is going to work in any simple string encoding, up to and including UTF-8 (but without a BOM). But don't try to format it for UTF-16 or anything exotic (like EBCDIC, or some such nuttery). It probably won't work there. The assumption is that character 10 (0x0A, if you prefer) is a \n character, and that 39 (or 0x27) is a single quote character.

And speaking of quote characters -- when you copy/paste from here, watch for any character encoding issues: this page is served as UTF-8, and auto-replaces quotes with "smart quotes", which you'll have to replace with simple quotes if you want to use the code.

Update: If you have a bash shell handy, this is also a quine:

bash: bash:: command not found

Proof:

[narc@eris ~]$ bash: bash:: command not found
bash: bash:: command not found
[narc@eris ~]$

Update 2007-12-10: This doesn't really belong in Projects...


Add your comment

 

XHTML: You may use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>