Mark McBride

When I want to graphically show a process is some percent complete on the command line, I use a simple Zsh script.

Usage
completion_bar.sh
Usage: completion_bar.sh <width> <numerator> <denominator> [ <charset> ]

I just decide how many characters wide I want the graphic to be and give it the numerator and denominator of the percent completion I want to depict. Here are a few examples:

10 characters, 13/45=29% completion
completion_bar.sh 10 13 45
##*-------
50 custom characters
completion_bar.sh 50 25 30 "|>:."
|||||||||||||||||||||||||||||||||||||||||>........
Block characters
completion_bar.sh 10 13 30 "█▓▒░"
████▒░░░░░
UTF-8 characters
completion_bar.sh 10 7 20 "⌾⨀◯◦"
⌾⌾⌾⨀◦◦◦◦◦◦

The script doesn’t use anything but ZSH to produce the output.

completion_bar.sh
#!/usr/bin/env zsh

if [[ -z ${1} ]] || [[ -z ${2} ]] || [[ -z ${3} ]]; then
    echo "Usage: $(basename $0) <width> <numerator> <denominator> [ <charset> ]"
    exit 1
fi

width="${1}"
numerator="${2}"
denominator="${3}"
charset="${4:="#*=-"}"
bar=""

if [[ "$denominator" -eq "0" ]]; then
    bar_segments_full="0"
else
    # float representing completion relative to width, e.g., 11.6 of width 12
    bar_segments_float="$(printf "%.1f\n" "$(( ${numerator}.0 * ${width}.0 / ${denominator}.0 ))" )"
    # split into whole and decimal components, e.g., 11.6 => 11 and 6
    bar_segments_whole="${bar_segments_float%%.*}"
    bar_segments_tenths="${bar_segments_float#*.*}"
fi

# render the characters depicting fully complete
for ((i=1; i<=$((${bar_segments_whole})); i++)); do
    bar+="${charset:0:1}"
done

# render the characters depicting partially complete
if [[ "$(( $bar_segments_whole + 1 ))" -le "$width" ]] && [[ "$bar_segments_tenths" -ne "0" ]]; then
    if [[ "$bar_segments_tenths" -ge "5" ]]; then
        bar+="${charset:1:1}"
    else
        bar+="${charset:2:1}"
    fi
fi

# render the characters depicting not yet complete
bar_segments_empty=$((${width} - ${#bar}))
for ((i=1; i<=${bar_segments_empty}; i++)); do
    bar+="${charset:3:1}"
done

echo "$bar"