See Also edit
Description edit
proc progres {cur tot} {
# if you don't want to redraw all the time, uncomment and change ferquency
#if {$cur % ($tot/300)} { return }
# set to total width of progress bar
set total 76
set half [expr {$total/2}]
set percent [expr {100.*$cur/$tot}]
set val (\ [format "%6.2f%%" $percent]\ )
set str "\r|[string repeat = [
expr {round($percent*$total/100)}]][
string repeat { } [expr {$total-round($percent*$total/100)}]]|"
set str "[string range $str 0 $half]$val[string range $str [expr {$half+[string length $val]-1}] end]"
puts -nonewline stderr $str
}VI 2007-02-09: Another one modeled after the one from wget. Auto updates every 5% or 5s.
32%|================..................................| 1600|ETA: 4sUpdated to print Total time taken at end - rather than reducing count.
proc progress_init {tot} {
set ::progress_start [clock seconds]
set ::progress_last 0
set ::progress_last_time 0
set ::progress_tot $tot
}
# We update if there's a 5% difference or a 5 second difference
proc progress_tick {cur} {
set now [clock seconds]
set tot $::progress_tot
if {$cur > $tot} {
set cur $tot
}
if {($cur >= $tot && $::progress_last < $cur) ||
($cur - $::progress_last) >= (0.05 * $tot) ||
($now - $::progress_last_time) >= 5} {
set ::progress_last $cur
set ::progress_last_time $now
set percentage [expr round($cur*100/$tot)]
set ticks [expr $percentage/2]
if {$cur == 0} {
set eta ETA:[format %7s Unknown]
} elseif {$cur >= $tot} {
set eta TOT:[format %7d [expr int($now - $::progress_start)]]s
} else {
set eta ETA:[format %7d [expr int(($tot - $cur) * ($now - $::progress_start)/$cur)]]s
}
set lticks [expr 50 - $ticks]
set str "[format %3d $percentage]%|[string repeat = $ticks]"
append str "[string repeat . $lticks]|[format %8d $cur]|$eta\r"
puts -nonewline stdout $str
if {$cur >= $tot} {
puts ""
}
flush stdout
}
}
# Sample Test:
progress_init 5000
for {set i 0} {$i < 6200} {incr i 200} {
progress_tick $i
after 200
}CAU: I wrote this some time ago as an exercise. It displays a fancy sliding bar for the user while a long running command is in progress.
#Use on bourne/korn shell.
# -- waitbar
#
# Shows a flashy progress bar to the user on their terminal while a
# background process executes.
#
# Uses a Tcl interpreter to manage the screen updating!
#
# Arguments:
# See usage message below. Function accepts EITHER a command line or a PID.
#
# Result:
# Outputs a wait bar on the terminal.
waitbar() {
unset pid cmdline
OPTIND=0
barLength=15
barTime=2000
barChars="-#"
sliderLength=3
reverse=0
usage="Usage: waitbar [ -l<bar-length> ] [ -s<slider-length> ] [ -t<bar-time> ] [ -d<display-chars> ] [ -r ] <pid> | <command-line>"
if [ $# -eq 0 ] ; then
echo "No options supplied!" 1>&2
echo "$usage" 1>&2
return 1
else
while getopts "l:t:d:s:r" opt "$@"
do
case $opt in
d)
barCharStr=$OPTARG
if [ `printf $barCharStr | wc -m` -eq 2 ] ; then
barChars=$barCharStr
fi
;;
l)
barLength=$OPTARG
;;
s)
sliderLength=$OPTARG
;;
t)
barTime=$OPTARG
;;
r)
reverse=1
;;
\?)
echo "$usage" 1>&2
return 1
;;
esac
done
fi
# Resolve whether were using a command line or a PID
shift `expr $OPTIND - 1`
if [ $# -ne 1 ] ; then
echo "$usage" 1>&2
return 1
fi
userOpt=`echo "$1" | nawk '{
if (match($0,"^[0-9]+$") > 0) {
printf "P"
} else {
printf "C"
}
}'`
if [ "$userOpt" = "C" ] ; then
cmdline="$1"
else
pid="$1"
fi
ttyStr=`tty`
# Lock the terminal from any distorting iuser input.
stty -echo
stty -echonl
{
if [ "$userOpt" = "C" ] ; then
eval "$cmdline &"
pid=$!
fi
# Only show the waitbar if script is being run from a terminal
if [ "$ttyStr" != "" ] ; then
echo "set pid $pid
set barLength $barLength
set barChars \"$barChars\"
set barduration $barTime
set lagLength $sliderLength
set reverse $reverse
"'
fconfigure stdout -buffering none
#set barChars "-#"
#set duration 10000
set duration 0
#set barduration 2000
#set barLength 15
#set lagLength 3
set barduration [expr $barduration * 1.0]
set interval [expr {round($barduration/$barLength)}]
set fillchar [string index $barChars 0]
set poschar [string index $barChars 1]
set finished 0
set timesofar 0
set bartime 0
set position 1
set forward 1
while {! $finished} {
set forebar ""
set aftbar ""
set posString ""
while {1} {
set posString "$poschar$posString"
set posStrLen [string length $posString]
if {(($posStrLen >= $lagLength) || ($posStrLen >= $position)) || \
( [expr {$barLength - $posStrLen}] <= [expr {$position-$lagLength}] ) } {
break
}
}
set posStrLen [string length $posString]
if {$position <= $barLength} {
set aftbar [string repeat $fillchar [expr $barLength - $position]]
}
set aftbarLen [string length $aftbar]
set forebarLen [expr {$barLength-($posStrLen+$aftbarLen)}]
set forebar [string repeat $fillchar $forebarLen]
set aftbar [string repeat $fillchar [expr {$barLength - ($forebarLen + $posStrLen)}]]
# There is a difference in how various unixes pass through data
# to tclsh, so in some cases, the <CR> will need to be protected
# with another slash. This is true on SunOS 5.8.
set outStr [format "\\r\[$forebar$posString$aftbar\]" ]
if {$reverse && (! $forward)} {
set outStr [format "\\r\[$aftbar$posString$forebar\]" ]
}
puts -nonewline $outStr
flush stdout
after $interval
incr bartime $interval
incr timesofar $interval
incr position
if {$position >= [expr {$barLength + $lagLength}]} {
set bartime 0
set position 1
set forward [expr {abs($forward -1)}]
}
if {$timesofar >= $duration} {
if {$duration == 0} {
set timesofar 0
if {[exec ps -opid= -p $pid] == ""} {
set finished 1
}
} else {
set finished 1
}
}
}
' | tclsh &
tclpid=$!
wait $pid
wait $tclpid
printf "\\r \\r"
else
wait $pid
fi
} 2> /dev/null
stty echo
stty echonl
return 0
}
