While creating a countdown timer in bash, I came up with the following code:
for ((n=15; n > 0; n--)); do
printf "Reload | $n" && sleep 1
done
This works fine, it keeps adding the printf
to the same line, as expected.
So I opened the documentation on tput
and found:
tput el1
Clear to beginning of line
And tried it out:
for ((n=15; n > 0; n--)); do
tput el1; printf "Reload | $n" && sleep 1
done
However, this adds a tab on each iteration, so the output becomes:
Reload | 15
Reload | 14
Reload | 13
Those outputs are on the same line, so the 'clear' works but for some reason is the cursor not restored to the first column.
I've managed to fix it by adding a carriage return (\r
) behind the printf
:
for ((n=15; n > 0; n--)); do
tput el1; printf "Reload | $n\r" && sleep 1
done
I've read quite some docs, but can't grasp why the \r
is needed here. Please point me to the right documentation/duplicate about this matter.
Compare el1
tput el1
Clear to beginning of line
and clear
tput clear
clear screen and home cursor
Note that clear
explicitly states that it moves the cursor; el1
does not. It only erases whatever was on the current line between the start of the line and the current cursor position, leaving the cursor where it is for the following text.
The carriage return, on the other hand, is typically interpreted as moving the cursor to the beginning of the current line without advancing to the next line. The corresponding terminal capability would be cr
.
A more robust solution would be to move the cursor first, then clear to the end of the line, and finally output your next bit of text. This handles the case where a new bit of text is shorter than the previous, which will be an issue when you switch from double-digit to single-digit numbers.
for ((n=15; n>0; n--)); do
tput cr el; printf "Reload | %2d" "$n"; sleep 1
done
(The %2d
is to ensure the single-digit values don't "jump" one space to the left.)