1

I want to make a quine .sh script, and this is what I've made so far:
quine.sh:

#!/bin/sh
q="#!/bin/sh\nq=$q;echo \$q";echo $q

Focus on this line:

q="#!/bin/sh\nq=$q;echo \$q";echo $q

At the first occurence of $q (in \nq=$q), I first want to set the rest of the variable, and then this part (something line setlocal enabledelayedexpansion in batch files). Note that I want a solution for sh, not bash or something else, as I want portability. Also, do not give me tips on how to make my code shorter etc. I just want a solution for the problem above.

1
  • If you read about how to write quines, like here, you would see that what you are looking for is simply printf, which a POSIX sh should have. What you call "delayed expansion" is merely string formatting.
    – jw013
    Feb 12 '16 at 14:32
1

If we wrap the initial string in 's instead of "s then the $q will not be immediately expanded. We can then expand it later using eval:

#!/bin/sh
q='#!/bin/sh\nq=$q;eval "echo \"\$q\""';eval "echo \"$q\""

Unfortunately the \n is not expanded, the 's and "s are lost, and the \"s become "s.

Output:

#!/bin/sh\nq=#!/bin/sh\nq=$q;eval "echo \"\$q\"";eval echo "$q"

We are quite close, but trying to fix the escaping with sed ends up becoming rather cumbersome.


jw013's link recommends a fairly understandable approach:

  • Part 1: Define some data (e.g. a variable) which contains the second part of the program
  • Part 2: Use the data to output the first part of the program, and then use the data to output the second part of the program. (Handle wrapping and escaping needed for part 1 here.)

Here is an initial crude attempt at that:

#!/bin/sh
data="echo -e \"#!/bin/sh\ndata=\"\$data\"\"\\n\$data"
echo -e "#!/bin/sh\ndata=\"$data\"\n$data"

Output:

#!/bin/sh
data="echo -e "#!/bin/sh
data="$data""
$data"
echo -e "#!/bin/sh
data="$data""
$data

This attempt suffers from the \n being always interpreted and the \s being lost. We need some way to escape the data string when we print it again.


Here is an improvement which uses multiple calls to echo in order to avoid the issues with \ns.

#!/bin/sh
data='echo "#!/bin/sh"\necho "data=$data"\necho -e "$data"'
echo "#!/bin/sh"
echo "data='$data'"
echo -e "$data"

It suffers from one tiny flaw which is hard to overcome, missing 's in the output (the middle echo):

#!/bin/sh
data='echo "#!/bin/sh"\necho "data=$data"\necho -e "$data"'
echo "#!/bin/sh"
echo "data=$data"
echo -e "$data"

That's all I have for you. Some starting points with escaping issues. Good luck!

2
  • Thanks, I'm accepting 'cause I've been looking for a damn solution for DAYS!
    – EKons
    Feb 15 '16 at 12:48
  • Thanks for the puzzle! I ended up chasing my tail trying to put the ' into a variable using quotes a="'". I should have used the solution they used in the bash quines here: a=\' Feb 16 '16 at 8:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.