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 retur
Inspired by How to get the cursor position in bash?
#!/bin/bash
lineformat="This is a very long line with a lot of stuff so they will take "
lineformat+="more than standard terminal width (80) columns... Progress %3d%%"
n=0
while [[ $n -ne 100 ]]; do
n=$((n+1))
printf -v outputstring "$lineformat" $n
twidth=$(tput cols) # Get terminal width
theight=$(tput lines) # Get terminal height
oldstty=$(stty -g) # Save stty settings
stty raw -echo min 0 # Suppres echo on terminal
# echo -en "\E[6n"
tput u7 # Inquire for cursor position
read -sdR CURPOS # Read cursor position
stty $oldstty # Restore stty settings
IFS=\; read cv ch <<<"${CURPOS#$'\e['}" # split $CURPOS
uplines=$(((${#outputstring}/twidth)+cv-theight))
((uplines>0)) &&
tput cuu $uplines # cursor up one or more lines
tput ed # clear to end of screen
tput sc # save cursor position
echo -n "$outputstring"
tput rc # restore cursor
sleep .0331s
done
echo
As tput cols
and tput lines
is initiated at each loop, you could resize window while running, cuu
argument will be re-computed.
trap WINCH
for querying terminal size only when window is resized newlines
for scrolling up before cuu
tput
There:
#!/bin/bash
lineformat="This is a very long line with a lot of stuff so they will take "
lineformat+="more than standard terminal width (80) columns... Progress %3d%%"
getWinSize() {
{
read twidth
read theight
} < <(
tput -S - <<<$'cols\nlines'
)
}
trap getWinSize WINCH
getWinSize
getCpos=$(tput u7)
getCurPos() {
stty raw -echo min 0
echo -en "$getCpos"
read -sdR CURPOS
stty $oldstty
IFS=\; read curv curh <<<"${CURPOS#$'\e['}"
}
oldstty=$(stty -g)
before=$(tput -S - <<<$'ed\nsc')
after=$(tput rc)
n=0
while [[ $n -ne 100 ]]; do
n=$((n+1))
printf -v outputstring "$lineformat" $n
getCurPos
uplines=$(((${#outputstring}/twidth)+curv-theight))
if ((uplines>0)) ;then
printf -v movedown "%${uplines}s" ''
echo -en "${movedown// /\\n}"
tput cuu $uplines
fi
printf "%s%s%s" "$before" "$outputstring" "$after"
sleep .05
done
downlines=$((${#outputstring}/twidth))
printf -v movedown "%${downlines}s" ''
echo "${movedown// /$'\n'}"
Yes, but it is not easy.
Your first and best options is ANSI Escape sequences and you can control cursor by this codes.
For compatibility of your script with everyone else's Terminal you should calculate the width / height of that Terminal.
Here using Xwininfow
you can check yours
wininfo | egrep -e Wid+ -e H+ -e A+
and the output for me will be:
Absolute upper-left X: 0
Absolute upper-left Y: 45
Width: 1600
Height: 855
Then in your script based on width / height you should update the cursor position or clear unused text on Terminal.
As user1934428 commented we have a better option by enabling two global variables using shopt
(= shell options)
>>> shopt | grep win
checkwinsize on
it is on so we can use them
>> echo $LINES
56
>> echo $COLUMNS
228
NOTE that such a task by python is much easier to do than using bash