なんで気になった?
私はgoで作成していたCLIアプリケーションを時々微改修していたのですが、ふと思い立って、多数のファイルを逐次処理する箇所にプログレスバーを表示しようとしていました。コマンドライン上でプログレスバーを更新するとなった時、簡単かつ正攻法である方法といえば、既にプログレスバーが表示されている行で、キャリッジリターンで行頭に飛び、全て上書きするというものが挙げられると思います。
普段私はそのアプリケーションをPowerShell上で動かしており、それに対応できる、最悪それだけには対応していれば良いという方針で方法を探っていました。
その中で、 PowerShellでは、キャリッジリターンは`r
で表現する という文を見つけました。PowerShell内で試してみたところ、実際そのようだと思わえました。
Write-Host "ab`rc" # Output: cb
なので……
func processFiles(fileNames []string) {
fileNum := len(fileNames)// ファイル数は2000とかそのくらいです
d := int(float64(fileNumber) / 100)
for index, fileName := range fileNames {
// ファイル処理
if (index+1) % 100 == 0 {
fmt.Print("`r") // PowerShell専用対応
astCount := int((index+1) / 100)
barCount := d - astCount
fmt.Print(strings.Repeat("*", astCount))
fmt.Print(strings.Repeat("-", barCount))
fmt.Printf(
"[%d/%d done.]",
index + 1,
fileNum
)
}
}
}
fmt.Print("`r") // PowerShell専用対応
fmt.Print("`r") // 元凶
どんどん伸びるプログレスバーになるはずだったもの
まあ、コンソールが中々のことになりました。
*--------[100/1000 done.]`r**--------[200/1000 done.]`r***-------[300/1000 done.]`r
...
実際はもっと酷かったです。
実際どうするべきだったか
一回頭がリセットされた後で、原因を探ろうと考えました。
とりあえず、まずは同じくCLIアプリケーションを作成でき、その中でも速やかに作成できる部類に入るJavaScriptで同様の現象が起こるか確かめてみました。
console.log('ab`rc');
# PowerShell
node test.js
# 宗派によってはこちらでも
deno run test.js
# Output: ab`rc
どうも、PowerShell上で実行だからといって、PowerShellで文字列をecho
なり Write-Host
した時とは状況が異なるようです。
そういうことなので、他の手段を試してみました。
console.log('ab\rc');
# PowerShell
deno run test.js # 私の宗派はこっちです
# Output: cb
一発目でビンゴ。
という訳でgoでもサクッとテスト用のコードを書いて実行してみました。
package main
import (
"fmt"
)
func main() {
fmt.Println("ab\rc")
}
# PowerShell
go run test.go
# Output: cb
やったぜ。
おまけ
他のシェルで使えるキャリッジリターンの記法が使えるならば、他のものも試したくなってきます。
console.log('\u001b[31mThis is red text.\u001b[0m');
// Outputは赤文字
package main
import (
"fmt"
)
func main() {
fmt.Println("\u001b[31mThis is red text.\u001b[0m")
}
// Outputは赤文字
最後に
PowerShellの echo
なり Write-Host
に`r
を入れ込んだ時の挙動と、コンソールアプリケーションのコードで`r
を標準出力させた時の挙動の差について、自分の中で納得する理屈が分からないのが現状です。
このあたりについて詳しい方がいらっしゃったら、コメントなどして頂けると有り難いです!
ここまで読んでくださり、ありがとうございます!