Differences between revisions 3 and 12 (spanning 9 versions)
Revision 3 as of 2021-08-13 23:06:45
Size: 1480
Editor: GreyCat
Comment: ... try just one category? I don't know why this doesn't work!
Revision 12 as of 2022-07-12 21:07:04
Size: 3133
Editor: emanuele6
Comment: add POSIX version of the last quine
Deletions are marked like this. Additions are marked like this.
Line 37: Line 37:
(May add more later if I figure them out.) This one consists of a function that uses `declare -f` to print its own definition.
Line 39: Line 39:
NB: there is an extra space after `f ()` and after `{` to match the output of `declare -f`.

{{{#!highlight bash
#!/bin/bash --
f ()
{
    printf '#!/bin/bash --\n';
    declare -f f;
    printf 'f\n'
}
f
}}}

Here's a variant using a similar technique:

{{{#!highlight bash
f ()
{
    printf "%s\n${!1} $1" "$(local -f ${!1})"
}
f FUNCNAME
}}}

'''Notes''': this one also has an extra space after the first two lines, ''and'' it must have no trailing newline at the end of the file.

And along the same lines - a `DEBUG` trap that prints its own definition:

{{{#!highlight bash
trap -- 'printf "%s\n:" "$(trap -p DEBUG)"' DEBUG
:
}}}

Bash can print the current command directly with an automatic variable for an easy quine.

{{{#!highlight bash
echo "$BASH_COMMAND"
}}}

ksh93 has a similar variable, which is only active within a DEBUG trap. This quine makes use of that:

{{{#!highlight ksh
trap -- x='${.sh.command}' DEBUG
trap
print -v _ x
}}}

This one uses `eval` together with an "assign default value" parameter expansion. It works from an interactive bash or ksh shell, and assumes (in fact, requires) that the variable `s` is not already defined:

{{{#!highlight bash
q=\' b=\\ eval ${s='echo q=$b$q b=$b$b eval \${s=$q$s$q}'}
}}}

It also relies on a particular implementation of `echo`, which differs between dash and bash. It doesn't work with dash's `echo`.

Alternative version that should work in any POSIX shell:
{{{#!highlight bash
IFS= q=\' b=\\ eval ${s='printf "IFS= %s %s %s %s %s\\n" q=$b$q b=$b$b eval \${s=$q$s$q}'}
}}}

Bash quine

A quine is a program that takes no input, and prints its own source code as output. Writing one is challenging in any language, and usually involves poking into the darkest, smelliest corners of the syntax.

If you've come across this page through some sort of wandering browsing, you might wish to stop reading after this introduction, and attempt to write a quine yourself. Reading the finished results here is not as educational as the struggle to write one. If on the other hand you've already struggled, either successfully or unsuccessfully, and would like to compare your results against someone else's, then read on.

Invalid quines

The classic shell approach would be something like

   1 #!/bin/sh
   2 cat "$0"

However, this is considered invalid, as it takes input from the file system.

The other classic shell approach would be the empty program. This one is considered to fail the spirit of the challenge, because it doesn't teach you much.

Valid quines

This first one is derived from the Java quine posted on the wikipedia page.

   1 #!/bin/bash
   2 q=(
   3 '#!/bin/bash'
   4 'q=('
   5 ')'
   6 'printf "%s\n" "${q[@]:0:2}"'
   7 'printf "\047%s\047\n" "${q[@]}"'
   8 'printf "%s\n" "${q[@]:2}"'
   9 )
  10 printf "%s\n" "${q[@]:0:2}"
  11 printf "\047%s\047\n" "${q[@]}"
  12 printf "%s\n" "${q[@]:2}"

This one consists of a function that uses declare -f to print its own definition.

NB: there is an extra space after f () and after { to match the output of declare -f.

   1 #!/bin/bash --
   2 f () 
   3 { 
   4     printf '#!/bin/bash --\n';
   5     declare -f f;
   6     printf 'f\n'
   7 }
   8 f

Here's a variant using a similar technique:

   1 f () 
   2 { 
   3     printf "%s\n${!1} $1" "$(local -f ${!1})"
   4 }
   5 f FUNCNAME

Notes: this one also has an extra space after the first two lines, and it must have no trailing newline at the end of the file.

And along the same lines - a DEBUG trap that prints its own definition:

   1 trap -- 'printf "%s\n:" "$(trap -p DEBUG)"' DEBUG
   2 :

Bash can print the current command directly with an automatic variable for an easy quine.

   1 echo "$BASH_COMMAND"

ksh93 has a similar variable, which is only active within a DEBUG trap. This quine makes use of that:

   1 trap -- x='${.sh.command}' DEBUG
   2 trap
   3 print -v _ x

This one uses eval together with an "assign default value" parameter expansion. It works from an interactive bash or ksh shell, and assumes (in fact, requires) that the variable s is not already defined:

   1 q=\' b=\\ eval ${s='echo q=$b$q b=$b$b eval \${s=$q$s$q}'}

It also relies on a particular implementation of echo, which differs between dash and bash. It doesn't work with dash's echo.

Alternative version that should work in any POSIX shell:

   1 IFS= q=\' b=\\ eval ${s='printf "IFS= %s %s %s %s %s\\n" q=$b$q b=$b$b eval \${s=$q$s$q}'}


CategorySillyThings

BashQuine (last edited 2022-07-12 22:52:49 by emanuele6)