I'm trying to create an update-able progress status. In order to do that, I need to be able to clear the last output in its entirety so that I can update it. Carriage returns can work, but when the output is longer than the terminal width and wraps around, it will fail to clear the last output. So I'm using tput:
n=0
while [[ $n -ne 100 ]]; do
n=$((n+1))
tput ed #clear
tput sc #save cursor
echo -n "Progress: ${n}%"
tput rc #restore cursor
sleep 1s
done
echo
But this will fail if the output is long enough that it forces the terminal to scroll up. When that happens, the saved cursor position is no longer correct and it will fail to clear the last output correctly.
For example, if the cursor is currently at the bottom of the terminal and the output is longer than the terminal width, it will force the terminal to scroll up, invalidating the previously saved cursor position.
So are there any ways to ensure that the cursor will never the end of the terminal in Bash? Or maybe some other alternative methods to prevent this problem?
EDIT: I made my own version based on F. Hauri's answer, simplified for my use case
#!/bin/bash
str=$(head -c 338 < /dev/zero | tr '\0' '\141')
len="${#str}"
col=$(tput cols)
lines=$(( ((len + col - 1) / col) - 1 ))
echo -ne "${str}\r"
(( len > col )) && tput cuu "$lines"
sleep 3s
tput ed