LoginSignup
11
10

More than 5 years have passed since last update.

シェル芸クワインの作り方

Last updated at Posted at 2017-10-07
1 / 24

自己紹介

@yasuhiroki
tw: @duck_yasuhiroki

シェル芸術<クワイン編>

そのシェルスクリプトもうちょっとシンプルに書けそう Tips集(Golf/シェル芸ではない)


シェル芸とは

マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理をCLI端末へのコマンド入力一撃で終わらすこと。あるいはそのときのコマンド入力のこと。

シェル芸の定義バージョン1.11


クワインとは

コンピュータプログラムの一種で、自身のソースコードと完全に同じ文字列を出力するプログラムである。2


シェル芸クワインとは

シェル芸であり、クワインである

$ echo $BASH_COMMAND
echo $BASH_COMMAND

$ echo $BASH_COMMAND | bash
echo $BASH_COMMAND

$ echo $BASH_COMMAND | bash | bash
echo $BASH_COMMAND

シェル芸クワインの実装例


ヒルベルト曲線シェル芸クワイン (前回発表)

n= h='l=\47L${r}FR${l}F${l}RF${r}L\47 r=\47R${l}FL${r}F${r}LF${l}R\47 %s l= r= eval echo \47$l\47 | { read a; b=${a%%%%F*}; echo "import sys;from turtle import *;speed(0);pensize(2);ms=min(screensize())*0.8;l=2*ms/(2**${#b}-1);up();setpos(-ms,-ms);down();${a}sys.exit()"; } | sed \47s/L/lt(90);/g;s/R/rt(90);/g;s/F/fd(l);/g\47 | python \n' s='n=\47%s\47 h=%s s=%s eval $\47printf "${h}${s}" "${n} eval"{,} "${h@Q}" "${s@Q}"\47' eval $'printf "${h}${s}" "eval ${n}"{,} "${h@Q}" "${s@Q}"'

山手線内回りシェル芸クワイン

n=0 y='5p2x5LqsIOaciealveeUuiDmlrDmqYsg5rWc5p2+55S6IOeUsOeUuiDlk4Hlt50g5aSn5bSOIOS6lOWPjeeUsCDnm67pu5Ig5oG15q+U5a+/IOa4i+iwtyDljp/lrr8g5Luj44CF5pyoIOaWsOWuvyDmlrDlpKfkuYXkv50g6auY55Sw6aas5aC0IOebrueZvSDmsaDooosg5aSn5aGaIOW3o+m0qCDpp5Lovrwg55Sw56uvIOilv+aXpeaarumHjCDml6Xmmq7ph4wg6bav6LC3IOS4iumHjiDlvqHlvpLnlLog56eL6JGJ5Y6fIOelnueUsAo=' l='convert -pointsize $(($(tput cols)/4)) -font ArialUnicode label:%s pbm:- | pbmtoascii 1>&2\n' s='n=%d y=%s l=%s s=%s eval $\47printf "${l}${s}\n" "$(echo ${y}|base64 --decode|xargs -n1|sed -n $((n%%29+1))p)" "$((n+1))" "${y@Q}" "${l@Q}" "${s@Q}"\47' eval $'printf "${l}${s}\n" "$(echo ${y}|base64 --decode|xargs -n1|sed -n $((n%29+1))p)" "$((n+1))" "${y@Q}" "${l@Q}" "${s@Q}"'

山手線内回りシェル芸クワイン

次は東京ー東京ー

image.png


山手線内回りシェル芸クワイン

東京の次はー有楽町ー

image.png


山手線内回りシェル芸クワイン

フォントサイズを小さくすれば鮮明な文字に

image.png


山手線内回りシェル芸クワイン

無事一周

image.png


シェル芸クワインのための必須技術


シェル芸クワインのための必須技術

  • s=1 echo ${s} では ${s} の値は出力されない
    • s=1 eval 'echo ${s}' なら ${s} の値は出力される
    • eval により s=1 が評価されてから echo ${s} が実行されるため

シェル芸クワインのための必須技術

  • s="%s" eval 'printf "${s}" "hoge"'hoge が出力される
    1. s="%s" eval 'printf "${s}" "hoge"'
    2. eval 'printf "${s}" "hoge"'
      (s="%s" が定義済みな状態)
    3. printf "${s}" "hoge"
    4. printf "%s" "hoge"

シェル芸クワインの基本形

比較的シンプルなクワインシェル芸の例

image.png

  • 全く同じコードが含まれている
    • クォートをエスケープしているか、していないかだけ
  • エスケープと %s の位置さえ間違えなければカスタムできる

↓コピペ用

s='s=%s eval $\47printf "${s}" "${s@Q}"\47' eval $'printf "${s}" "${s@Q}"'

シェル芸クワインの発展形

image.png

  • 変数を増やした例
    • n=%d により動的に n の値を変更できる
    • $((++n)) にしているが、別に ${RANDOM} などでもよい
      • 同じコードを2箇所に追加することさえ忘れなければOK
      • ただし空白や改行やクォートが混ざるとエスケープが難しいので注意
      • % も混ざると大変

↓コピペ用

n=1 s='n=%d s=%s eval $\47printf "${s}" "$((++n))" "${s@Q}"\47' eval $'printf "${s}" "$((++n))" "${s@Q}"'

シェル芸クワインのデバッグ方法

  • bash -xv で地道に頑張る
  • 慣れてくると目で気付く(末期)

山手線内回りシェル芸クワインの解説

使用しているコマンド

  • base64 コマンド
    • 駅名を base64 でエンコードしている
    • 別に不要なのだけど 東京 有楽町 ... と文字列があるとネタバレになるので隠したかった
  • tput コマンド
    • ターミナルの横幅を取得する

山手線内回りシェル芸クワインの解説

使用しているコマンド

# 漢字を表示できるフォントを探すシェル芸
$ convert -list font | grep Font: | awk '{print $2}' | xargs -I@ echo 'echo @; convert -pointsize 20 -font @ label:漢字OK pbm:- | pbmtoascii' | bash

山手線内回りシェル芸クワインの解説

image.png


m=60 n=-1 l='echo "$(yes @ | head -n%d | xargs | tr -d @)^" 1>&2\n' l2='echo -e "$(yes @ | head -n%d | xargs | tr -d @)/$(yes @ | head -n%d | xargs | tr @ " ")\\\\" 1>&2\n' s='m=60 n=%d l=%s s=%s eval $\47printf "${l}${s}" "$((m-n-2))" "$((n+1))" "$((n+1))" "${l@Q}" "${s@Q}"\47' eval $'printf "${l}${s}" "$((m-n-2))" "$((n+1))" "${l2@Q}" "${s@Q}"'

おしまい


11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10