やりたかったこと
なんとなくコンソールに「zzz」と立体(平面)的に出力させるコマンドラインツールを作りたくなった。完成形が以下である。(Windows?知らない子ですね。。。)
ソースについてもいたってシンプルで、単に3種類の大きさのZのAAを順に出力しているだけである。
package main
import (
"fmt"
"os"
"time"
)
const (
BLUE = "\033[34m"
END = "\033[0m"
)
func main() {
defer fmt.Fprint(os.Stdout, END)
fmt.Fprint(os.Stdout, BLUE)
for i := 0; i < 5; i++ {
for _, zzz := range zzzs {
fmt.Fprintf(os.Stdout, "\r%s", zzz)
time.Sleep(500 * time.Millisecond)
fmt.Fprint(os.Stdout, "\033[13A")
}
fmt.Fprintln(os.Stdout, "")
fmt.Fprint(os.Stdout, "\033[1A")
}
}
package main
var zzzs = [4]string{zzz1, zzz2, zzz3, zzz4}
const zzz1 = `
ZZZZZZZZZZ
ZZ
ZZ
ZZ
ZZ
ZZZZZZZZZZ`
const zzz2 = `
ZZZZZZZZZZZZZZZZ
ZZ
ZZ
ZZZZZZZZZZ ZZ
ZZ ZZ
ZZ ZZ
ZZ ZZ
ZZ ZZ
ZZZZZZZZZZ ZZZZZZZZZZZZZZZZ`
const zzz3 = `
ZZZZZZZZZZZZZZZZZZZZZZZZ
ZZ
ZZ
ZZ
ZZZZZZZZZZZZZZZZ ZZ
ZZ ZZ
ZZ ZZ
ZZZZZZZZZZ ZZ ZZ
ZZ ZZ ZZ
ZZ ZZ ZZ
ZZ ZZ ZZ
ZZ ZZ ZZ
ZZZZZZZZZZ ZZZZZZZZZZZZZZZZ ZZZZZZZZZZZZZZZZZZZZZZZZ`
const zzz4 = `
`
エスケープシーケンスの操作
上記のツールを作成する上で、解決しないといけない課題は大きく分けて2つあった。
- 文字色の変更: 必要性があるわけではなかったが、なんとなく見栄えが良さそうなのでZのAAの文字色を変更した。
- カーソルの移動: 普通にZのAAを順に出力するだけでは、添付のgifにあるような同じ画面が更新され続けるような見た目にすることは出来ない。前に表示されたZのAAが残ったままである。
1, 2 の問題はともにエスケープシーケンスを用いることにより解決することができ、実際のところGo特有というわけでもなく、rubyなど別の言語でも同様の手法を使える。
詳しくはエスケープシーケンスでググるといい。
1. 文字色の変更
標準出力に"\033[33m"
, "\033[37m"
などを出力することにより、その出力後の文字色を変更できる([とmの間の数字を変更)。必ず処理終了後は文字色を戻すこと。
const (
BLUE = "\033[34m"
END = "\033[0m"
)
func main() {
defer fmt.Fprint(os.Stdout, END)
fmt.Fprint(os.Stdout, BLUE)
2. カーソルの移動
前述の通り、普通にZのAAを順に出力するだけでは、添付のgifにあるような同じ画面が更新され続けるような見た目にできず、前に表示されたZのAAが残ったままである。
これを解決するにはZのAAが出力されるたびに、ZのAAの表示位置のカーソル位置をコマンドを実行した場所まで上に移動させる必要がある。
これは、標準出力に"\033[1A"
, "\033[13A"
などを出力することにより実現できる([とAの間に数字を変更)。Aの部分をB, C, Dと変えることによりカーソル位置を上下左右に変更できる。
func main() {
defer fmt.Fprint(os.Stdout, END)
fmt.Fprint(os.Stdout, BLUE)
for i := 0; i < 5; i++ {
for _, zzz := range zzzs {
fmt.Fprintf(os.Stdout, "\r%s", zzz)
time.Sleep(500 * time.Millisecond)
fmt.Fprint(os.Stdout, "\033[13A")
}
fmt.Fprintln(os.Stdout, "")
fmt.Fprint(os.Stdout, "\033[1A")
}
}
最後に
エスケープシーケンスを用いると他にも様々なことが実現でき、それを特にコマンドラインツールの作成において役立つ。
こんな画面表示をコマンドラインツールで実現したいがどうするればいいのだろうと思った際には一度エスケープシーケンスに調べてみると道が開けるかもしれない。