How to have an in-place string that updates on stdout
The solution for one string which will replace whole string
fmt.Printf("\033[2K\r%d", i)
For example, it correctly prints from 10 to 0:
for i:= 10; i>=0; i-- {
fmt.Printf("\033[2K\r%d", i)
time.Sleep(1 * time.Second)
}
fmt.Println()
which previous answers don't solve.
stdout
is a stream (io.Writer
). You cannot modify what was already written to it. What can be changed is how that stream's represented in case it is printed to a terminal. Note that there's no good reason to assume this scenario. For example, a user could redirect stdout to a pipe or to a file at will.
So the proper approach is to first check:
- if the stdout is going to a terminal
- what is that terminal's procedure to overwrite a line/screen
Both of the above are out of this question's scope, but let's assume that a terminal is our device. Then usually, printing:
fmt.Printf("\rOn %d/10", i)
will overwrite the previous line in the terminal. \r
stands for carriage return
, implemented by many terminals as moving the cursor to the beginning of the current line, hence providing the "overwrite line" facility.
As an example of "other" terminal with a differently supported 'overwriting', here is an example at the playground.
Use this solution if you want to rewrite multiple lines to the output. For instance, I made a decent Conway's "Game of Life" output using this method.
DISCLAIMER: this only works on ANSI Terminals, and besides using fmt
this isn't a Go-specific answer either.
fmt.Printf("\033[0;0H")
// put your other fmt.Printf(...) here
Brief Explanation: this is an escape sequence which tells the ANSI terminal to move the cursor to a particular spot on the screen. The \033[
is the so-called escape sequence, and the 0;0H
is the type of code telling the terminal move the cursor to row 0, column 0 of the terminal.
Source: https://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements