Backspacing in Bash
Asked Answered
D

4

7

How do you backspace the line you just wrote with bash and put a new one over its spot? I know it's possible, Aptitude (apt-get) use it for some of the updating stuff and it looks great.

Deckhouse answered 10/1, 2011 at 6:49 Comment(1)
could you give an example of what you want because it's not exactly clear to meFaggot
O
15

Try this:

$ printf "12345678\rABC\n"
ABC45678

As you can see, outputting a carriage return moves the cursor to the beginning of the same line.

You can clear the line like this:

$ printf "12345678\r$(tput el)ABC\n"
ABC

Using tput gives you a portable way to send control characters to the terminal. See man 5 terminfo for a list of control codes. Typically, you'll want to save the sequence in a variable so you won't need to call an external utility repeatedly:

$ clear_eol=$(tput el)
$ printf "12345678\r${clear_eol}ABC\n"
ABC
Oceanus answered 10/1, 2011 at 7:14 Comment(2)
Thanks man. I found that tput is exactly what I am looking for. It's a little awkward to output with it, but that's cool.Deckhouse
How come I've never seen this command! I remember a big script where I actually used the control characters in the more awkward ways. @KyleHotchkiss don't complain, look at how control characters are output here for example (type this in a console: echo -e '\033[1mbold\033[0m\033[4memphasis\033[0m')Stalky
Q
1

It's not really clear to me what you want, but, depending on your terminal settings you can print ^H (control H) to the screen and that will back the cursor up one position.

Also note that some terminals have the ability to move the cursor to the beginning of the line, in which case you'd move to the beginning of the line, print enough spaces to overwrite the entire line (Usually available from $COLUMNS) and then print any message or whatever.

If you clarify exactly what you want and I can answer you I'll update my answer.

Quadruple answered 10/1, 2011 at 6:52 Comment(3)
Does that allow you to write over the stuff already there or just push what is already there down?Deckhouse
@Kyle: It moves the cursor back 1 character.Quadruple
@Kyle: It overwrites. To be more specific, it's not bash you're talking to but the terminal which could either be a gui application or the CRT terminal driver or an actual physical terminal.Compensable
C
1

Here's an example using the find command & a while-read loop to continually print full file paths to stdout on a single line only:

command find -x / -type f -print0 2>/dev/null | while read -d $'\0' filename; do 
   let i+=1
   filename="${filename//[[:cntrl:]]/}"   # remove control characters such as \n, \r, ...
   if [[ ${#filename} -lt 85 ]]; then
      printf "\r\e[0K\e[1;32m%s\e[0m  %s" "${i}" "${filename}"
   else
      printf "\r\e[0K\e[1;32m%s\e[0m  %s" "${i}" "${filename:0:40}.....${filename: -40}"
   fi
done; echo
Christychristye answered 10/1, 2011 at 10:5 Comment(0)
S
1

The original question was for an animated progress bar (in apt-get) but it appears that nobody really answered that original question.

Either way I wrote this a bit of code a little while ago based on the top answer to this StackOverflow Thread. There are many beautifully complicated progress bars, but none of them "count-down" or "disappearing" progress bar. I also did not address the data or placement that this bar would likely represent in a real-world application. Depending what one is measuring, there is no such single solution to apply to all use cases. Thus, I leave that part of the problem to the reader.

Fast, Bash, and no forks

#!/usr/bin/bash
    
bar='###################################################################'
for (( i=${#bar}; i>0; i-- )); do
    echo -ne "${bar:1:$i}-\r"
    sleep .1s
done

After 0.3s

 _$ #################################################################'

After 1.8s

 _$ ##################################################

After 4.6s

 _$ ###################

and so on.

Bar Can be any character or length

bar1='#######'

or

bar2='++++++++++++'

Bash for loop

for (( i=${#bar}; i>0; i-- )); do

Bash parameter expansion gives the length of the string variable

i=${#bar}

Echo with suppress newline flag and interpret escaped chars flag -n -e

echo -ne

Bash Substring Expansion variable $i expands to the number of chars in string: ${bar} on the first iteration and then counts down from there. This could also be done with a negative offset.

${parameter:offset:length}

e.g.

${bar::$i}

Bar can be replaced by other chars or even whitespace; the carriage return "backspaces" the rightmost char, then a single digit and replace some other char or whitespace, e.g. a hyphen '-'

-\r

or

+\r

Configurable timing; sleep takes integers and floats as input, so configuring this to run every half-second or multiple fractions of a second like 2.7 seconds

sleep .1s

Segovia answered 8/2 at 23:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.