動く!電光掲示板シェル芸
⚠注意⚠: 点滅GIF画像が出てくるので、明るい部屋で画面から十分画面から離れてご覧ください。
この記事はシェル芸 Advent Calendar 2019とklis Advent Calender 2019のクロスポストになりました。
まえがき
今回の記事では、動くタイプの電光掲示板シェル芸について解説します。
具体的には文字を電光掲示板ライクに変換して、文字を画像にするtextimg
コマンドのオプションを色々使って動かします。
基本的(?)な電光掲示板シェル芸については@yami_buta氏が本AdventCalendarで過去3回ほど解説[1]をされているので、先にそちらの方に目を通されることをおすすめします。
おさらい 〜電光掲示板シェル芸とは〜
「LED表示みたいな画像を生成する」[2]シェル芸。
▼点滅とか…[4]
やってみる
STEP0: 電光掲示板文字っぽく出力
今回は文字Qiita
を動かしたいと思います。
まずdenkoh
関数を定義します。(定義ツイート)
この関数は文字を任意の文字でAAのように変換したものを返し、簡単に電光掲示板風に変換します。
最近だと@jiro4989氏がコマンドにしたもの[8]もあるのでそちらを使っても良いです。
# denkoh <電光掲示板風にしたい文> <背景文字> <前景文字> <粗さ>
# dtimgだと:
# dtimg <電光掲示板風にしたい文> -b <背景文字> -g <前景文字> -F <粗さ>
# .bash_aliases`などに追記しておくと便利。
denkoh(){
echo -e "$1"|textimg -F$4|convert - txt:-|awk -F'[, ]' \
'NR>2{printf($1==0)?"\n":($4==0)?a:b}' a="$2" b="$3";echo
}
これを使うと、
$ denkoh "Qiita" " " "■ " 20
■■■ ■■■
■■■■■■ ■■■ ■■■
■■■■■■■■ ■■■ ■■■ ■■
■■■ ■■■ ■■■ ■■■ ■■
■■ ■■■ ■■
■■ ■■■ ■■■■■ ■■■■■ ■■ ■■■■■■
■■ ■■■ ■■■■■ ■■■■■ ■■■■■■■■ ■■■■■■■■
■■ ■■■ ■■■ ■■■ ■■■■■■■■ ■■■ ■■■
■■ ■■■ ■■■ ■■■ ■■ ■■■
■■ ■■■ ■■■ ■■■ ■■ ■■■■■■■
■■ ■■■ ■■■ ■■■ ■■ ■■■■■■■■
■■ ■■■ ■■■ ■■■ ■■ ■■■ ■■■
■■ ■■ ■■■ ■■■ ■■ ■■ ■■■
■■■ ■■■ ■■■ ■■■ ■■ ■■ ■■■
■■■■■■■■ ■■■■■■■■ ■■■■■■■■ ■■■■■■ ■■■■■■■■
■■■■■■ ■■■■■■■■ ■■■■■■■■ ■■■■■■ ■■■■■■■■
■■■■■■ ■■■■ ■■■
■■■■
■■■
という具合に文字が出力できます。
この出力をtextimg
に標準入力で渡すと画像になります。
$ denkoh "Qiita" " " "■ " 20|textimg -o qiita.png
STEP1: 点滅
点滅させてみましょう。
同じ行数の空行を出力し、行数指定(textimg
の-l
オプション)で[文字部分n行]->[空行部分n行]
となるように調整してコマを切り替えGIF化します。
ここでは任意の空行を作るため、eval 'echo;'{<任意数個カンマ>}
とします。eval 'echo;'{,,,,}{,,,}
とすると5*4=20回echo
が評価されて20行分空行が作れます。
ちなみに数で明示的に空行を作るならseq <任意行数>|tr -d 0-9
でも同じことができます。
また複数コマンドの標準出力をまとめてパイプ先コマンドに渡す時は(cmd1;cmd2)|cmd3
とします。便利〜
#全体の行数の半分を-lに指定
$ (denkoh "Qiita" " " "■" 20;eval 'echo;'{,,,,,}{,,} )|wc -l
42
$ (denkoh "Qiita" " " "■" 20;eval 'echo;'{,,,,}{,,,})|textimg -al21 -o tenmetsu1.gif
目に痛いときは-d
オプションで速度を落としましょう。(デフォルトは20ms)
$ (denkoh "Qiita" " " "■" 20;eval 'echo;'{,,,,}{,,,})|textimg -al21 -d50 -o tenmetsu2.gif
いい感じです。
色コードの指定[9]で色をつけることもできますが、色のついた絵文字を指定することで簡単に色をつけられます。また後述のlolcat
という出力を虹色にするコマンドとも親和性が良いのでそれを使用しても楽しいです。
$ (denkoh "Qiita" " " "🍀" 20;eval 'echo;'{,,,,}{,,,} )|textimg -al21 -o tenmetsu3.gif -d50
STEP2: 縦スクロール
次は縦に動かします。
-S
オプションは、デフォルトで1行ずつ移動します。
$ (eval 'echo;'{,,,,}{,,,};denkoh Qiita " " "🍀" 20)|textimg -aSl21 -o tatesc1.gif
-W
オプションで任意の行数移動。
$ (eval 'echo;'{,,,,}{,,,};denkoh Qiita " " "🍀" 20)|textimg -aSl21 -W3 -o tatesc2.gif
そして-E
オプションで、EOSでまた行頭にループさせます。
$ (eval 'echo;'{,,,,}{,,,};denkoh Qiita " " "🍀" 20)|textimg -aSEl21 -W3 -o tatesc3.gif
空行を減らして-d
でコマの切り替え速度をアップ!
$ (eval 'echo;'{,,,,}{,,,};denkoh Qiita " " "🍀" 20)|textimg -aSEl21 -W3 -o tatesc4.gif
STEP3: 横スクロール
電光掲示板でよくある横方向のスクロール。これを実現するにはsed
を使ってdenkoh
出力を任意文字分を行末から行頭へ回転移動させることを繰り返します。
#一旦出力を変数に格納
$ s="$(denkoh Qiita ' ' '🍀' 20)"
$ for i in $(seq 10) #ずらす回数分ループ, 一度に5文字ずつずらす
do echo "$s"|sed -E 's/(.{'$[i*5]'})(.*)/\2\1/'
done|textimg -al22 -o yoko.gif #もともとの行数+2
いい感じです。
この処理は、denkohmove
という関数に定義しておくと便利です。(定義ツイート)[10]
# denkohmove <電光掲示板風にしたい文> <背景文字> <前景文字> <粗さ> \
# <移動する幅> <ずらす回数(=コマ数)> <出力時の解像度> <コマの切り替え速度>
# ex: denkohmove ' 🚙 🚗 🚙 🚗' ' ' '⚪' 10 \
# 8 7 5 10
denkohmove(){
local text back front line width flame resolute speed
text="$1" back="$2" front="$3" line="$4"
width="$5" flame="$6" resolute="$7" speed="$8"
s="$(denkoh ${text} ${back} ${front} ${line})"
for i in $(seq ${flame})
do echo "$s"|sed -E 's/(.{'$[i*width]'})(.*)/\2\1/'
done|textimg -asl$[line+1] -F${resolute} -d${speed}
}
STEP4: 明暗
複数文字でのdenkoh
出力を組み合わせ繰り返すことで明暗の反復を表現できます。
「明」は中身のある文字(例:●,▲
)、「暗」はない文字(例:○,△
)で表現します。
$ s="`denkoh Qiita ' ' ■ 20`"
$ for i in ● ○
do echo -e "$s"|sed "s/■/$i/g"
done|textimg -al22 -o meimetsu1.gif
明暗の文字を連続して切り替えるとメリハリ(?)が付きます。
$ s="`denkoh Qiita ' ' ■ 20`"
$ for i in ● ○ ▲ △ ● ○ ▲ △ #明暗の文字を交互に配置する
do echo -e "$s"|sed "s/■/$i/g"
done|textimg -al22 -o meimetsu2.gif
また出力時の行数を2倍にすると明暗を並べて表現できます。
$ s="`denkoh Qiita ' ' ■ 20`"
$ for i in ● ○ ▲ △ ● ○ ▲ △
do echo -e "$s"|sed "s/■/$i/g"
done|textimg -al44 -o meimetsu3.gif
コマンドラインを虹色にするのでおなじみlolcat
コマンド[11]で着色してみます。-f
オプションは、パイプで渡しても色コードが失われないようにするオプションです。また-p
オプションは虹の次の色へ変わるまでの間隔、-F
オプションは色の機微が遷移する間隔を指定します。
$ s="`denkoh Qiita ' ' ■ 20`"
$ for i in ● ○ ▲ △ ● ○ ▲ △
do echo -e "$s"|sed "s/■/$i/g"
done|lolcat -f|textimg -al22 -o meimetsu4.gif
いいですね。
ちなみに、STEP3とこの手法を組み合わせて各ループごとの偶数番目と奇数番目で前景文字を異なる文字で置換することで、冒頭例のようにチカチカした感じを表現できます。ここでは「明」を白混じりの🍺
、「暗」を黄いろい🌟
に指定しています。
#ずらす作業の関数化
$ f(){ echo "$d"|sed -E 's/(.{'$[i*9]'})(.*)/\2\1/';}
$ d="$(denkoh Qiita ' ' '🍺' 20)"
$ for i in {1..5}
do [[ $((i%2)) = 0 ]]&&f || { f|sed 's_🍺_🌟_g';} #奇数番目ループなら置換
done|textimg -al22 -o chika.gif
派手〜!
シェル芸botに投稿!
STEP5:シェル芸botは皆さんご存知、フォロワーの#シェル芸
付きのツイートをコマンドとして評価し結果をツイートで返すbotです。
シェル芸botには、コンテナ内の/images/
直下に画像ファイルをコマンド内で配置することでその画像を投稿できる機能があります。(静/動画ともに最大4枚まで)
textimg
にはこのために画像の出力先を/images/o.[png|gif]
にできる-s
オプションが用意されています。上記の例の-o
オプション部分を削除して代わりに-s
を使いましょう。
また、投稿が1ツイートに収まりきらない場合や、他人がツイートで定義した関数・変数を使用したいなら、コメント付き引用RTでそのツイートをRTすることで実現できます。(参考: denkohの定義ツイートとそれを引用したツイート)
備考: 投稿できない時 && テスト環境の紹介
しかし、今回取り上げたGIF画像を実行しようとしてもうまく結果がbotに返されないこともあります。理由としては、
- シェル芸botの実行TLE(制約20s)
-
timeout 20 <ツイート>
で実行している(?)
-
- 画像サイズ超過
- 静止画 : 5MB
- GIF動画 : 15MB(スマホなら5MB)
が挙げられ、殆どは前者が原因です。計算量を落とすには、
-
textimg
での出力時に-F
オプションでデフォルトの20より少ない数を指定して解像度を落とす(denkoh
なら最後の数字) -
denkoh
で出力する行数を減らす - STEP3ならずらす幅を大きくしループを少なくしてコマを減らす
などの方法があります。投稿できる計算量にしてからツイートを投稿しましょう。
シェル芸bot作者の@theoldmoon0602氏によってbotの最新dockerイメージが配布[12]されているのでそれを使用してもいいですが、画像を逐一確認しながら20秒制限を調整するには、以下のWeb実行環境(各種ネタコマンド完備)でテストするのが無難です。[13]
- SGWeb(https://shellgei-web.net/)
- @kekeho氏作
- OSS[14]
- 現在デプロイされているのは約半年前のイメージ
- 一部の
ネタコマンドが使えない
- websh(https://websh.jiro4989.com/)
- @jiro4989氏作
- OSS[15]で、純Nim製
- 最新イメージがデプロイされている
実行されるまで#シェル芸
ツイートを連投しTLを汚しながらコマンドを調整する方法もありますが...
結論
textimg
便利すぎ!!!!![16]
最後に
いかがでしたか?
このようにコマンドライン上だけで多種多様なGIF画像ができてしまいます。
またこの他にも今回紹介した例を応用して様々な画像が作れます。
▼例: 斜めスクロール
▼例: 複数文字を順に[17]
お試しあれ。
余談ですが、今回紹介したtextimgやdtimgはシェル上に画像を投稿するために作られたコマンドです。他にもシェル芸bot上には様々なシェル芸愛好家(通称:シェル芸人)の方々が、主にシェル芸botで使うことを目的として作成したクソ便利なコマンド群が導入されています。[18]
是非本記事で使用したコマンドや他の楽しいコマンド群を使って#シェル芸
でシェル芸botに投稿してみましょう!
<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://t.co/x68LPj5tnf">https://t.co/x68LPj5tnf</a> <a href="https://t.co/H8lXmzqh3U">pic.twitter.com/H8lXmzqh3U</a></p>— シェル芸bot (@minyoruminyon) <a href="https://twitter.com/minyoruminyon/status/1209375210643701760?ref_src=twsrc^tfw">December 24, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
-
https://twitter.com/minyoruminyon/status/1181228580711235584
今回はこれを動かします。
こんなことができます。 ↩︎ -
https://twitter.com/minyoruminyon/status/1206658567551344641
▼縦スクロール[5]
↩︎ -
https://twitter.com/minyoruminyon/status/1209334806502346752
▼掲示板っぽい横スクロール[6]
↩︎ -
https://twitter.com/minyoruminyon/status/1209367740609204225
▼明暗[7]
↩︎ -
https://twitter.com/minyoruminyon/status/1185642956155281408 ↩︎
-
2019年12月現在 ↩︎
-
textimg
はwebshと同じ作者の方が作成している。 ↩︎ -
https://twitter.com/minyoruminyon/status/1209425831367282688 ↩︎
-
典型例:super_unko,ojichat
それでは皆様、良いシェル芸ライフを! ↩︎
Discussion