Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

So, when wget gets a web page, it shows you a status bar that indicated how much the file(s) is/are downloaded. It looks like this:

25%[=============>______________________________________] 25,000 100.0K/s (underscores are spaces; I just couldn't figure out how to get more than one consecutive space in there)

However, instead of writing another line to stdout and adding another progress bar, it updates it, like this:

50%[===========================>________________________] 50,000 100.0K/s

And wget isn't the only example of this, either. For example, when you pipe something into less and then exit, your original prompt is still there, along with the result of whatever commands that you ran previously. It's like you never left.

So, my questions are, what is this called, how do I implement it, does it only work for a single line at a time, and can I use this in C?

share|improve this question
4  
I recommend reading BashFAQ 44. You may find it interesting. –  jw013 Jul 14 '12 at 20:08
4  

2 Answers 2

up vote 13 down vote accepted

First of all your question has nothing to do with bash but with the terminal. The terminal is responding for displaying the text of the programs and bash itself has no control over the programs once they launched.

Terminals offer control sequences to control color, font, cursor position and more. For a list of standardized terminal sequences have a look at http://www.termsys.demon.co.uk/vtansi.htm You can for example

  • position the cursor at the beginning of the line
  • delete the line afterwards
  • write a new line

to create a progress bar.

More advanced terminal escape sequences are typically terminal dependent, e.g. work only with Eterm or xterm. ncurses - is a programming library which to create interactive programs with the terminal so you won't have to use escape sequences.

How to overwrite an existing line with terminal sequences

echo long text
sleep 1
printf "\033[1A"  # move cursor one line up
printf "\033[K"   # delete till end of line
echo foo

How to overwrite an existing line without terminal sequence

One simple solution is to not write a newline at the end but write carriage return, which basically resets the cursor to the beginning of the line, e.g:

echo -n first 
sleep 1 
echo -ne "\rsecond"
echo

The \r or carriage return will put the cursor at the beginning of the line and allows you to overwrite the content of the line.

Switch between buffers like less or vi

The behavior of less is also due to a more advanced terminal feature, the alternate screen:

In VT102 mode, there are escape sequences to activate and deactivate an alternate screen buffer, which is the same size as the display area of the window. When activated, the current screen is saved and replaced with the alternate screen. Saving of lines scrolled off the top of the window is disabled until the normal screen is restored. The term‐ cap(5) entry for xterm allows the visual editor vi(1) to switch to the alternate screen for editing and to restore the screen on exit. A popup menu entry makes it simple to switch between the normal and alternate screens for cut and paste.

http://rosettacode.org/wiki/Terminal_control/Preserve_screen lists some example how to do it yourself, either via tput or via some escape sequences.

share|improve this answer

Instead of using echo which automatically appends a newline to the string, use printf "%s\r" whatever -- the carriage return sends the cursor to the beginning of the current line. example:

seq 1 15 | while read num; do printf "%2d\r" $num; sleep 1; done; echo ""
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.