ターミナルで区切り線っぽいものを出したい

f:id:monozukuri-bu:20171003201907j:plain

どーも、xyakenです。普段はRubyでコード書いてますが、今回もコンソールネタです。今回は、macOS SierraUbuntu 16.04 LTS、CentOS 7.3で動くことを確認しています。

普段、ターミナルを操作していて、切り取り線的なものが欲しくなる時ないですか? たとえば、findしたり、grepしたり、あるいはコケるのが予想されるテストコードを走らせるときとか結構な量の出力があるので、どこからがいま実行したコマンドの出力かなと探さないといけなくなります。

そういう時に、こんな感じで切り取り線打てたら素敵じゃないですか?

f:id:monozukuri-bu:20170806000533p:plain

方法

やっていることはごく単純です。

  • ターミナルの横幅の長さを取得する
  • 横幅に合わせた文字列を作る
  • 文字列に色付けして出力
  • 以上

ターミナルの横幅を取得するにはtput colsを使います。こんな感じで、ターミナルの横幅が得られます。

[vagrant@localhost ~]$ tput cols
102
[vagrant@localhost ~]$ tput cols
92

横幅に合わせた文字列を作るにはprintfコマンドを使います。おなじみのprintfなので特に説明は不要でしょう。

[vagrant@localhost ~]$ printf "%50s\n" hoge
                                              hoge

tputコマンドと組み合わせるには以下のようにします。

[vagrant@localhost ~]$ printf "%$(tput cols)s\n" hoge
                                                                                        hoge

さて、色をつけて切り取り線っぽくしてみます。色をつけるにはANSI エスケープコードというものを使います。

printf "\e[46m$(printf %$(tput cols)s)\e[0m\n"

これでCyanの切り取り線が表示されます。ANSIエスケープコードや色指定については、以下が詳しいです。

www.mm2d.net

さらに、毎度毎度上記のコマンドを指定するのも面倒ですし、どうせ何かのコマンドを実行する前に切り取り線を出力するわけですからまとめて指定できるようにしたいところです。というわけで、.bashrcファイルに以下のような関数を追加します。

kiri() {
    printf "\e[46m$(printf %$(tput cols)s)\e[m\n"
    "$@"
}

"$@"というのがミソで関数に指定した引数をそのまま実行させています*1。実行例は以下の通り。

f:id:monozukuri-bu:20170806000618p:plain

応用として切り取り線に実行時間を出してみます。

kiri() {
    printf "\e[46m$(printf %-$(tput cols)s $(date +%Y/%m/%d_%H:%M:%S))\e[m\n"
    "$@"
}

実行例は以下の通り。

f:id:monozukuri-bu:20170806000656p:plain

おまけ:切り取り線っぽくする

こんなの切り取り線じゃないやい! って人向け。

kiri() {
    local width=$(tput cols)
    local kiri_line=$(seq $width | xargs -I{} printf -- '---8<---')
    # ダイレクトにprintf ... | head -c とかやると「シグナル13によって終了しました」とかでるので
    kiri_line=$(echo $kiri_line | head -c $width)
    printf "\e[46m$kiri_line\e[m\n"
    "$@"
}

---8<-切り取り線-8<---みたいにしたかったんですが、どーにもマルチバイト文字が絡むとえらく面倒なことになるっぽいのでやめました。

f:id:monozukuri-bu:20170806000709p:plain

*1:わかっている人には常識ですが$@ではダメです。例えば、ls 'a b'というコマンドは$@だとls a bになってしまいます。"$@"ならls 'a b'になってくれます