echo without newline

I am trying to make a download progress meter with bash and I need to echo a percentage without making a newline and without concatenating to the last output line.

The output should replace the last output line in the terminal.

This is something you see when wget or curl downloads files. That's what I am trying to do, but I don't know how.

Any pointers?

for progress bar
try printf .

You'll probably need echo -n ... in addition to this : Cursor Movement

PS: echo is a buit-in for some shells that do not respect -n, so call the actual echo from whence/which it is found, or echo "....\c" works in ksh. Put a carriage return as first character and overwrite the line with enough characters to ensure all old data is gone. The cursor will rest to the right. You might want to pad a few spaces for added readability, as a blinking block cursor where you are focusing is just asking for an epileptic seizure. :smiley:

printf can do a lot more than skipping the line feed, so that is a nice tool to adopt. It is a bit different, using it in shell not C/C++/JAVA, since without extra effort data are all character arrays.

To use printf safely, do printf "%s" "mystring"

Since the first string is a format string, % characters in it will be interpreted as formatting specifiers. %s means 'string'. So %s by itself will print things as they're given without a newline.

If you'd just done printf "mystring" it might do strange things if mystring has a % in it anywhere.

1 Like

How about this in bash:

#!/bin/bash
COLS=0
[ -t 1 ] && COLS=$(tput cols)
 
function show_pct
{
   pct=$1
   [ $COLS -lt 10 ] && return
 
   if [ $pct -lt 0 ]
   then
       printf "\r%-*s\r" $((COLS-2))
       return
   fi
 
   if [ $pct -eq 0 ]
   then
       fill=""
       printf -v rest "%-*s" $((COLS-10))
   else
     printf -v fill "%-*s" $((pct*(COLS-10)/100))
     printf -v rest "%-*s" $((COLS-10-(pct*(COLS-10)/100)))
   fi
   printf "\r%4d%% [%s%s]" $pct "${fill// /=}" "${rest// /.}"
}
 
for((val=0;val<101;val++)) {
    show_pct $val
    sleep 0.05
}
show_pct -1

---------- Post updated at 08:11 AM ---------- Previous update was at 07:51 AM ----------

Replace last line of function with

 printf "\r       %s%s]\r%4d%% [%s" "$fill"  "${rest// /.}" $pct "${fill// /=}" >&2

To output to stderr and leave cursor at % complete position, however this outputs nearly twice as many characters for each percentage.

It's also worth "remembering" the last percentage displayed and not outputting anything if the percentage is the same.

If you do not want to clutter logs, you can write such to the screen >/dev/tty even on systems lacking /dev/stderr.