!!!この記事は全体的にあまり役に立たないネタ記事です!!!
cat
コマンドってあるじゃないですか。ファイルの中身を標準出力に出すやつ。
あれ元々はファイル結合のためのコマンドで、2つのファイルを順に標準出力に出せば結合できるよねって奴で、concatnateがコマンド名の由来らしいんですが、まあそれはどうでもいいです。今回やりたいのは「cat
と打ち込んだら🐈が表示される」というただそれだけのネタなので。
FishとかZshとかその他別のシェルを使っている方には申し訳ないんですが、Bashを前提にします。まあそんなに大きなスクリプトではないので(やりたい人がいるかは別として)別のシェル向けに移植するのは不可能ではないとは思います。
プロンプトを変更する方法
Bashのプロンプトは $PS1
という名前の環境変数で表示内容を設定できます。$PS1
の内容の文字列中に $VAR
のような環境変数名を入れておくと、プロンプト表示時に毎回それを評価してくれます。そこで今回は、 .bashrc
の末尾に
export PS1="\$CAT_PS1$PS1"
source cat_hook.bash
という行を追加して、 $CAT_PS1
の内容がコマンド実行ごとに変わるような仕組みを cat_hook.bash
で実装するのを目指していこうと思います。
コマンドの実行を検知する
Bashの組み込みコマンドに trap
というものがあり、本来の使い道はスクリプトでシグナルハンドラを実装するためのものだと思うのですが、Bashには DEBUG
という疑似シグナルがあり、これをトラップするとコマンドの実行直前に呼び出される関数を定義できます。
function cat_hook() {
# TODO
}
trap cat_hook DEBUG
実行中のコマンドは $BASH_COMMAND
という環境変数に入っているので、これを利用します。
コマンドが cat
かどうか調べる(?)
$BASH_COMMAND
を分解して先頭が cat
かどうかを調べる、みたいなのを考えたのですが、それだとパイプの後ろにある cat
を検知できないんですよね。パイプまで含めた構造を分析するとか…等と考えましたが、そもそも別に cat
コマンド実行した時以外に🐈が出てきて何も問題はないことに気づきました。猫は多ければ多いほど良いので。
そしたらもう $BASH_COMMAND
に cat
が含まれていさえすればいいですよね。なんなら cat
が二回出てきたら二匹🐈を出せばいい。
という訳でこうなります。
local N=$(echo "$BASH_COMMAND" | grep -i -o cat | wc -l)
grep -i -o cat
で cat
の出現箇所のみを抜き出せるので、 wc -l
で行数を数えれば cat
が出現した回数になります。あとは回数分🐈を結合した文字列を $CAT_PROMPT
に代入すれば良いです。ちなみに大文字小文字は区別しません。猫は多ければ多いほど良いので。
せっかくなので絵文字の種類を増やしたい。
こうしてプロンプトには🐈が出てきてくれるようになりましたが、🐈🐈🐈🐈🐈と一種類の絵文字が並んでいるだけだとちょっと単調だな、と思うようになりました。幸いUnicodeには猫の絵文字が色々含まれているので、それらをランダムに表示するようにしたいです。
まず猫の顔文字として「😿 😾 🐱 🙀 😺 😽 😼 😸 😹 😻」があります。
あと、「🐾」という肉球の絵文字もあるのでこれも猫の足跡ということで採用します。
「🐈⬛ 」という黒猫を表す絵文字もあるのですが、これはUnicodeコードポイント3つ分の結合文字で、私のターミナル環境だと文字幅がおかしくなってしまうので断念しました。
Unicodeに含まれる猫の絵文字はこれで全部?
いいえ、もう一つあります。「𓃠」です。そう、ヒエログリフですね。せっかくなのでこれも追加します。
猫の顔文字が10文字、肉球とヒエログリフを含めて12文字です。
元々🐈を表示しようと思っていたのでこれが多めになるように10文字まで増やして、
local CATS=(🐈 🐈 🐈 🐈 🐈 🐈 🐈 🐈 🐈 🐈 😿 😾 🐱 🙀 😺 😽 😼 😸 😹 😻 🐾 𓃠)
という配列からランダムに抽選を行うようにしました。
Bashには RANDOM
という組み込みの変数があり、この値は評価するごとに変わるのでこれを利用します。この変数がどういうアルゴリズムを利用していてどの程度偏っているかとか良く知りませんが、まあ別に偏っていて問題があるタイプの乱数の使い方ではないので適当にやっていきます。
という訳で最終的にこうなりました。
# cat_hook.bash
function cat_hook() {
local N=$(echo "$BASH_COMMAND" | grep -i -o cat | wc -l)
local NEW_PS1=''
local BR=''
local CATS=(🐈 🐈 🐈 🐈 🐈 🐈 🐈 🐈 🐈 🐈 😿 😾 🐱 🙀 😺 😽 😼 😸 😹 😻 🐾 𓃠)
for i in $(seq $N); do
NEW_PS1="$NEW_PS1${CATS[$(($RANDOM % ${#CATS[*]}))]}"
BR=$'\n'
done
export CAT_PS1="$NEW_PS1$BR"
}
trap cat_hook DEBUG
export CAT_PS1=''
🐈が出るときと出ない時でプロンプトの入力位置がズレるのはちょっと使いづらいかなと思ったので、🐈が出た時は改行するようにしています。
実際に実行してみるとこのようになります。
個人的にヒエログリフ猫はSSRなので猫十連ガチャ大成功の動画が撮れました。
cat
が含まれていればカウントされるので category
などの別の単語にも反応しますが、問題はありません。猫は多ければ多いほど良いので。
なおこれだとコマンドの出力の最後の行に絵文字が連続しているかのように見えてちょっと戸惑ってしまうかもしれませんが、全く問題はありません。猫は人間を戸惑わせて作業の邪魔をするものなので。
以上です。みなさんの元に猫と平和がありますように。