Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Shebang Quine (github.com/geon)
162 points by geon on May 20, 2016 | hide | past | favorite | 54 comments


Here's my favorite one ever...

http://aem1k.com/world/


This one is also amazing.

https://github.com/mame/quine-relay


I remember when this one was released and we were passing the link around on e-mail threads in the office. It's pretty amazing and insane.


Hmm ... 100 langs circuit, impressive ... thumbnail of code ... %&$#!!

https://github.com/mame/quine-relay/blob/master/thumbnail.pn...

(Attention to detail, they haz it.)


wow, that's incredible. there's, like, 4 different techniques going on in there that I don't understand- and I would have said I understood javascript pretty well.


Wow, can someone explain what is going on in here?


This is extremely cool, however the source code does look a little different than the output (the output only has '#' chars, but the source has letters and other chars besides #). Does that still count as a quine? (don't really care though... this is very cool).

Any idea how this works? It's just to much for my mind to bear I think.


I'm not sure what you're talking about. The output is the entire source with the central globe rotated by a user-selectable number of degrees, including 0. The output isn't just the globe in the center.

Edit: Ah, nvm. It looks like this is a Javascript port of a famous Ruby quine from 2010, the Qlobe[1].

[1]: http://d.hatena.ne.jp/ku-ma-me/20100905/p1


Well, not really. I checked the source and you can see here:

https://jsfiddle.net/f17yr7qh/

For example, line 9 of the source:

~(32sin(o)/* , (W#####Xx######.P^ T % */sin(.5+y/7))\

You can see that there are more chars than just '#' inside the "globe", like '(W' and 'Xx' and '.P^'

I even changed those inside the globe and the effect is non obvious. Sometimes it stops working sometimes it works fine with other chars. No idea why.


Is this technically a quine though?

In any other language, a program that opens and prints file containing its own source code is not considered a quine.


Probably not.


It could be called a "boring quine" whereas the better ones could be called "pure quines". I'd still call it a quine though.


Hmm, when we speak of quining, we ask "How in X programming language, do we write a program that outputs it's own text".

But in what language is this "program" written?

The best I can guess is that the unix shebang hack/convention is a (very, very minimal) language all of its own.


I is not 'exactly' a quine, because the tool 'cat' is a program on its own, and not a shell command. Still, it is an entertaining and unexpected outcome.


My favorite pseudo-quine is just an empty file. Works in Bash, PHP, Node, Perl, Python, Ruby, and many others I'm sure.


I'm curious to know where the line of a "program" goes. I imagine a OS without file system, but only with functions (like as if emacs was an OS). Would a function then be called a program?


That's not the issue, really. The issue is whether the program has access to itself as input. This one does, so it's not a quine. But it's cool.


Well, if your EmacsOS allocates exclusive adress-space for the function-call, so that it can be executed in a very own execution context, independent of other function-calls... then you could call it a program.


In that definition, it seems like DOS OSes never had programs.


Yeah, I would call it a quine of the binary loader, basically.


If anyone's curious, I wrote a blog post a while ago on how to write programs that obtain their own source code: http://malisper.me/2016/04/20/writing-self-referential-progr...


A more philosophical shebang that I like is

   #!/bin/rm


Very fun.

For those who are puzzled by the term "quine": http://meta.codegolf.stackexchange.com/questions/4877/what-c...


I like the fact that #!/proc/self/exe causes the interpreter to be the calling program (since the interpreter is evaluated in the context of the calling program, from the kernel).


I was thinking of unorthodox uses for the shebang, and realized cat gives you a very succinct quine.

Any other funny commands? ls -l is cool too.


Ages ago I wrote a simple command that let you do shell scripting in the shebang line. http://reasonableapproximation.net/2010/07/27/silly-things-t...

I'm not sure I've used it since, but I still like the xgraph thing.


Very interesting and a good read. I was not aware that you could pass an argument in the shebang line.


It’s often used to have your shell scripts fail fast by using `#! /usr/bin/bash -e`; which you could also do by using `set -e` at the beginning of the script but that’s less elegant.


This is pretty great little read, much appreciated


  #!/bin/rm
  #!/sbin/md5
  #!/usr/bin/file
  #!/usr/bin/du -h
And yet another quine:

  #!./quine
  cat $0
Edit: I was not sure about #!/sbin/poweroff, and I cannot try now, so removed.


I'm fairly sure `#!./quine` will cause an error because there's a limit of 5 recursive checks to find the interpreter of a script (fs/binfmt_script.c).


Ran it, works. I'm on freebsd 10.3 BTW.


On Linux you get ELOOP. How does that resolution even work on FreeBSD? Why does it resolve to $SHELL (the file resolves to itself).


Yeah, I don't see that working unless the shebang is changed to `#!/bin/sh`?


execve(2) on my machine defines ELOOP lie this: Too many symbolic links were encountered in translating the pathname.

Refer to sys/kern/imgact_shell.c and ^do_execve in sys/kern/kern_exec.c, I skimmed but could not find why it ran.


Presumably then, whatever shell you're using decides to just execute the code as a subshell rather than use execve(2). Can you dtrace it to figure out whether it actually calls execve(2)?


After running dtrace as

  $ sudo dtrace -n 'syscall::execve*:entry { printf("%s %s", execname, copyinstr(arg0)); }'
I had this output

    0  51617                     execve:entry sh ./quine
    1  51617                     execve:entry sh /bin/sh
    1  51617                     execve:entry sh /bin/cat
Altho this is the first time I use dtrace. I can try to run another command you can ask me to.

My login shell is the Bourne shell. However I tried bash, csh and tcsh too, it works, so it's probably the system level code that substitutes /bin/sh (maybe because it's my login shell?) to the interpreter.


I think shells are doing that. Otherwise you wouldn't see the execve("/bin/sh") syscall entry (it would get silently translated inside the kernel).


Huh...yea, I never though about how the first argument to a program is always itself.


rm, with self cleaning action!


Is this technically a quine? It uses its own file as an input. I think that may technically disqualify it from quineness.


Here's a quine written as an ld linker script:

    TARGET(binary)
    OUTPUT_FORMAT(elf32-i386)
    ENTRY(_start)
    SECTIONS
    {
        . = 2M;
        .text 2M: {
            _start = .;
            BYTE(0xb8); LONG(4)         /* mov $4, %eax */
            BYTE(0xbb); LONG(1)         /* mov $1, %ebx */
            BYTE(0xb9); LONG(data);     /* mov data, %ecx */
            BYTE(0xba); LONG(data_len); /* mov data_len, %edx */
            BYTE(0xcd); BYTE(0x80);     /* int $0x80 */
            BYTE(0xb8); LONG(1)         /* mov $1, %eax */
            BYTE(0x31); BYTE(0xdb);     /* xor %ebx, %ebx */
            BYTE(0xcd); BYTE(0x80);     /* int $0x80 */
            data = .;
            *(.data);
            data_len = ABSOLUTE(. - data);
        }
    }
Building and running it:

    /tmp$ ld -T quine.ld quine.ld -o quine
    /tmp$ ./quine | diff -s quine.ld -
    Files quine.ld and - are identical


So if anyone is interested here are some "Elixir" quine attempts: http://elixirgolf.com/articles/elixir-quine-self-replicating...


Haha treating cat as an interpreter just sends the script on stdin.


Actually, sends the name of the script as an argument to cat, not stdin.


First argument in bash is the name of the file. So, this is a quine, since the output of running it is the contents of the script, which is:

#!/bin/cat

[EDIT] as pointed out, I misspoke, and this is false.


I don't think bash is involved here?


I don't think so either. It's something in the implementation of `execv` I think.

    #include <unistd.h>                                                             
                                                                                
    int main() {                                                                    
        execl("cat-quine", "cat-quine", NULL);                                      
        return 0;                                                                   
    }
Is sufficient to have this work.


An entire generation of programmer has grown up not knowing that this is implemented in the kernel.


I remember being surprised by this and then realising, "wait, of course it's in the kernel -- that's so much nicer from a usability and sanity standpoint".


It's implemented in the kernel. Look at fs/binfmt_script.c in the Linux kernel source tree for an example.



More precisely:

  - The shell finds opens up the file you want to execute

  - It gets the first line of the file

  - It figures out what program to execute

  - It calls fork()

  - In the new process, it executes the program (using exec()) and passes the file as the input to the program.


The shell is not involved in looking at the first line of the program, that's what happens in `exec`.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: