💾 Archived View for jfh.me › posts › 2019-02-29-quine.gmi captured on 2022-04-29 at 11:23:57. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2021-11-30)

-=-=-=-=-=-=-

Bash Quine

I wanted to see what it's like to write a quine. The challenge is pretty simple to understand: write a program that takes no input and can print itself.

Quine Wiki

I had heard of quines before but had never looked at one. After looking at the Wiki page for a while I diced to try to write one on my bus ride. I figured that writing it in Go or Javascript would probably be a little too familiar, so I tried to write it in bash. This is what I ended up with:

#!/bin/bash
# Quine John Hilliard

prog=(
    '#!/bin/bash'
    '# Quine John Hilliard\n'
    'prog=('
    ')'
    'q=$(printf "\x27")'
    'for i in \`seq 0 2\`; do'
    '    echo -e "${prog[$i]}"'
    'done'
    'for i in \`seq 0 13\`; do'
    '    echo "    $q${prog[$i]}$q"'
    'done'
    'for i in \`seq 3 13\`; do'
    '    echo "${prog[$i]}" | sed "s:\\\\\\`:\\\\`:g"'
    'done'
)
q=$(printf "\x27")
for i in `seq 0 2`; do
    echo -e "${prog[$i]}"
done
for i in `seq 0 13`; do
    echo "    $q${prog[$i]}$q"
done
for i in `seq 3 13`; do
    echo "${prog[$i]}" | sed "s:\\\\\`:\\\`:g"
done

Since I don't know bash that well, I'm not even sure how much sense this makes. Looping using ~seq~ feels weird. Especially since all of the bounds of the lists are hard coded.

The hardest part of the of the bash implementation is actually all of the escaping. Line 17 and 28 took a while to figure out. It would have been a lot easier if I used single quotes in ~sed~. But then escaping a single quote on line 17 was very hard to figure out.

Other than that, the structure of the application pretty much looks the same as the reference Java implementation from the Wiki page.

The way I ended up thinking about this is that the program has code and strings. The code needs to print out strings that represent the code itself. In terms of printing, I had to print the code that's before the strings, then print the strings themselves as strings, then print the code that's after the strings.

I don't know if I can explain quines better than explanations I've found online, but at least now I think I understand it.

Just to make sure it actually works, hashing the code and hashing the output gives the same result.

$ shasum quine.sh
21415e04c597d28058aed0163f2e501a0bcd36ac  quine.sh
$ ./quine.sh | shasum
21415e04c597d28058aed0163f2e501a0bcd36ac  -
$ ./quine.sh | bash | bash | bash | shasum
21415e04c597d28058aed0163f2e501a0bcd36ac  -

Another cool property of the quine is that we can keep passing the output to bash and it's going to have the same result.