13

I am writing a installation script and would like to display the status of the script as it progresses.

example:

var1="pending"
var2="pending"
var3="pending"

print_status () {
echo "Status of Item 1 is: "$var1""
echo "Status of Item 2 is: "$var2""
echo "Status of Item 3 is: "$var3""
}

code that does something and then refreshes the
output above as the status of each variable changes.
user2704404
  • 149
  • 1
  • 1
  • 8
  • Try `clear`. It erases the screen. For more advanced tricks, use something like `dialog`. – choroba Aug 21 '13 at 16:28
  • 1
    Could you clarify what you mean by "refreshes"? Do you mean you want to have some "form" or "screen" of output where only certain fields update? And that there may be multiple such fields at a given time? Or does status of item2 only start after item1 has completed (and likewise item3 after item2)? – lurker Aug 21 '13 at 16:34

5 Answers5

30

This code should give you the idea:

while :; do
    echo "$RANDOM"
    echo "$RANDOM"
    echo "$RANDOM"
    sleep 0.2
    tput cuu1 # move cursor up by one line
    tput el # clear the line
    tput cuu1
    tput el
    tput cuu1
    tput el
done

Use man tput for more info. To see the list of capabilities use man terminfo

Aleks-Daniel Jakimenko-A.
  • 10,335
  • 3
  • 41
  • 39
7

I find another solution which is not mentioned in existing answers. I am developing program for openwrt, and tput is not available by default. The solution below is inspired by Missing tput and Cursor Movement.

- Position the Cursor:
  \033[<L>;<C>H
     Or
  \033[<L>;<C>f
  puts the cursor at line L and column C.
- Move the cursor up N lines:
  \033[<N>A
- Move the cursor down N lines:
  \033[<N>B
- Move the cursor forward N columns:
  \033[<N>C
- Move the cursor backward N columns:
  \033[<N>D

- Clear the screen, move to (0,0):
  \033[2J
- Erase to end of line:
  \033[K

- Save cursor position:
  \033[s
- Restore cursor position:
  \033[u

As for your question:

var1="pending"
var2="pending"
var3="pending"

print_status () {
    # add \033[K to truncate this line
    echo "Status of Item 1 is: "$var1"\033[K"
    echo "Status of Item 2 is: "$var2"\033[K"
    echo "Status of Item 3 is: "$var3"\033[K"
}

while true; do 
    print_status
    sleep 1
    printf "\033[3A"    # Move cursor up by three line
done
Woody Huang
  • 462
  • 5
  • 11
3

Look at this:

while true; do echo -ne "`date`\r"; done

and this:

declare arr=(
  ">...."
  ".>..."
  "..>.."
  "...>."
  "....>"
)

for i in ${arr[@]}
do
  echo -ne "${i}\r"
  sleep 0.1
done
rook
  • 5,880
  • 4
  • 39
  • 51
1

You can use the carriage return to change text on a single status line.

n=0
while true; do
  echo -n -e "n: $n\r"
  sleep 1
  n=$((n+1))
done

If you can put all your counters on one line

n=0
m=100
while true; do
  echo -n -e "n: $n  m: $m\r"
  sleep 1
  n=$((n+1))
  m=$((m-1))
done

This technique doesn't seem to scale to multiple lines, though it does have the benefit over tput that it works on dumb terminals (like Emacs shell).

seanmcl
  • 9,740
  • 3
  • 39
  • 45
0

This does not completely solve your problem but might help; to print the status after the execution of each command, modify PS1 like this:

PS1='$PS1 $( print_status )'
Fabio A. Correa
  • 1,968
  • 1
  • 17
  • 26