自己紹介
@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}"'
山手線内回りシェル芸クワイン
次は東京ー東京ー
山手線内回りシェル芸クワイン
東京の次はー有楽町ー
山手線内回りシェル芸クワイン
フォントサイズを小さくすれば鮮明な文字に
山手線内回りシェル芸クワイン
無事一周
シェル芸クワインのための必須技術
シェル芸クワインのための必須技術
-
s=1 echo ${s}
では${s}
の値は出力されない-
s=1 eval 'echo ${s}'
なら${s}
の値は出力される -
eval
によりs=1
が評価されてからecho ${s}
が実行されるため
-
シェル芸クワインのための必須技術
-
s="%s" eval 'printf "${s}" "hoge"'
はhoge
が出力されるs="%s" eval 'printf "${s}" "hoge"'
-
eval 'printf "${s}" "hoge"'
(s="%s"
が定義済みな状態) printf "${s}" "hoge"
printf "%s" "hoge"
シェル芸クワインの基本形
比較的シンプルなクワインシェル芸の例
- 全く同じコードが含まれている
- クォートをエスケープしているか、していないかだけ
- エスケープと
%s
の位置さえ間違えなければカスタムできる
↓コピペ用
s='s=%s eval $\47printf "${s}" "${s@Q}"\47' eval $'printf "${s}" "${s@Q}"'
シェル芸クワインの発展形
- 変数を増やした例
-
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
コマンド- ImageMagick に含まれる画像変換コマンド
- 漢字の文字列を画像に変換
-
pbmtoascii
コマンド- 画像をアスキーアートに変換
- 参考)https://twitter.com/eban/status/813261361622884352
# 漢字を表示できるフォントを探すシェル芸
$ convert -list font | grep Font: | awk '{print $2}' | xargs -I@ echo 'echo @; convert -pointsize 20 -font @ label:漢字OK pbm:- | pbmtoascii' | bash
山手線内回りシェル芸クワインの解説
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}"'