'How to overwrite a multiline string in bash?
I have this code snippet, which allows to overwrite a string in bash if used multiple times:
echo -ne "String 1 \r"
echo -ne "String 2 \r"
Output:
String 2
However, the string is not overwritten if the string is wider than the terminal window:
echo -ne "Very very long string without any embedded newline charactes that is longer than the window width \r"
echo -ne "String 2 \r"
Output:
Very very long string without any embedded newline charactes that is longer than the window width
String 2
How can I force overwrite for the entire string, independent of the terminal window's size?
Helpful answers do not:
- assume that I do not write until the bottom of the terminal window (see above requirement regarding independence of window size)
- assume that clear may be used in this context
Solution 1:[1]
Assumptions:
- code generates output that may display on more than one line in the console/window (either multi-line variable w/ embedded carriage returns or just a really long line that causes a wrap when it hits the 'end' of the console/window)
- output does not cause the terminal to 'scroll up' (eg, program does not start printing output in the last line of the console/window
- do not know how many console/windows lines will contain the output string
First thing we'll do is provide a string that's actually longer than my console/window.
# 'stty -a' shows my terminal width ('columns') is 87, so 200 should be a long-enough string to play with
$ printf -v longstring '%0.sx' {1..200}
$ echo "${#longstring}:${longstring}"
200:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
To simulate 'backing up to front of line' we can use tput
, eg:
erase=$(tput ed) # save control codes for 'clear to end of line'
clear # clear console/window to insure we're not generating output at/near bottom of console/window
printf "\n\n################ begin output"
tput sc # save current cursor position
for i in {1..5}
do
printf -v count "%0s" $i
echo -en "${count} ${longstring} EOS\r"
tput rc # move cursor back to our save point
sleep 1
printf "${count} short string${erase}"
tput rc
sleep 1
done
# pick enough `\n` to get us 'past' our lines of output
printf "\n\n\n################ end output"
On the first pass through the loop we see:
########### start test
01 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx EOS
And one second later we see:
########### start test
01 short string
On subsequent passes through the loop the output line is overwritten with 02 xxx...
, 02 short string
, 03 xxx...
, 03 short string
, 04 xxx...
, 04 short string
, 05 xxx...
and then finally:
########### start test
05 short string
########### end test
Solution 2:[2]
echo 'Very very long string without any embedded newline charactes that is longer than the window width'
echo -e '\e[1A\e[KString 2'
String 2
return to the previous line using \e[1A and clear that line using \e[K
Test
for((i=2000; i>=0; i -=25))
do
sleep 0.01
echo -e "\e[1A\e[KString $i"
done
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |