連休何も予定がなく時間を持て余しているので、Bashのクワインについて考えてみました。
さっきのやつの無駄な部分を除去。このアプローチだとこの辺が限界かな。 pic.twitter.com/6ymbsohpMR
— tama (@mscle11) 2020年8月12日
クワイン(Quine)とは
自分自身と同じ文字列を表示するプログラムをクワイン(Quine)といいます。
Bashでクワイン(Quine)を作る
最初に示したクワインが出来上がるまでの考えを、順を追って解説してみます。
ベース
echo
で echo
を表示するものをベースにします。
$ echo 'echo hoge' echo hoge
eval
を導入
ベースの hoge
の部分を変数化します。
そのままだと変数 $a
が展開されないので eval
を導入します。
$ a='echo $a';$a $a $ a='echo $a';eval $a echo $a
表示の調整
元のプログラムに近づくように表示を調整します。
$ a='echo a="$a;eval \$a"';eval $a a=echo a="$a;eval \$a";eval $a
シングルクオートを表示する
Bash ではシングルクオート内でシングルクオートが使えないため、 苦肉の策として変数にシングルクオートを突っ込みます。
$ a='echo a="$b$a$b;b=\\$b;eval \$a"';b=\';eval $a a='echo a="$b$a$b;b=\\$b;eval \$a"';b=\';eval $a $ a='echo a="$b$a$b;b=\\$b;eval \$a"';b=\';eval $a | bash a='echo a="$b$a$b;b=\\$b;eval \$a"';b=\';eval $a
完成!
シングルクオートの扱いについて
シングルクオートを表示するには ASCII コードを使うという方法もあります。
echo
では e オプションを使って次のように書くとシングルクオートが表示されます。
$ echo -e \\x27 '
これを上記のクワインに組み合わせると、次のようになります。
$ a='echo a="$(echo -e \\x27)$a$(echo -e \\x27);eval \$a"';eval $a a='echo a="$(echo -e \\x27)$a$(echo -e \\x27);eval \$a"';eval $a
本当は次のようにしたいのですが、 \x27
と表示されてほしいところもシングルクオートになってしまうため、
苦肉の策で $(echo -e \\x27)
としています。
$ a='echo -e a="\x27$a\x27;eval \$a"';eval $a a='echo -e a="'$a';eval \$a"';eval $a
こちらの記事にある例では、 printf
を使っているようです。
こっちの方が echo
を使うよりも若干文字数が削減できますね。
$ printf \\x27 ' $ printf \\47 '
eval
を使わずにできるか
上で紹介した記事でも同じように、コマンド文字列を変数に代入
+ eval
というアプローチをしていました。
それでは、eval
を使わずにクワインを作ることはできるのでしょうか。
...と思って数時間あれこれ考えてみましたが、eval
を使わないクワインは思いつきませんでした。
作れる作れないの話は、理論計算機科学の話になりそうですが、もうその辺の特徴づけがあったりするんですかね?
長くなりそうなのでこの話はこの辺で...(知ってる方がいればコメントください)