Skip to content

Instantly share code, notes, and snippets.

@rwperrott
Last active July 24, 2024 10:47
Show Gist options
  • Select an option

  • Save rwperrott/9f636e4695d671ad3933939dd32513e3 to your computer and use it in GitHub Desktop.

Select an option

Save rwperrott/9f636e4695d671ad3933939dd32513e3 to your computer and use it in GitHub Desktop.
A bash progress bar with fine resolution and tput formatting.
#!/usr/bin/bash
#
# Based off:
# https://www.baeldung.com/linux/command-line-progress-bar
# https://ss64.com/bash/tput.html
#
BAR_CHARS=" ▏▎▍▌▋▊▉█"
BAR_SCALE=2
repeat() {
s=$1
n=$2
if ((n <= 0)); then
echo ""
else
printf "$s%.0s" $(seq "$n")
fi
}
progress() {
pre=$1
flags=$2
current=$3
total=$4
if ((current >= total)); then
echo -en "\r"
tput el
echo "$flags" "${pre}DONE"
else
div=${#BAR_CHARS}
((div--))
todo_char=${BAR_CHARS:0:1}
done_char=${BAR_CHARS:div:1}
# calculate bar-size dynamically, so always fits well.
((bar_width = $(tput cols) - ${#pre} - 9))
((bar_size = bar_width * div))
echo "$flags" "$flags" "${pre}["
tput smul
if ((current <= 0)); then
bar_todo=$(repeat "$todo_char" "$bar_width")
echo -n "${bar_todo}"
percent="0.00"
else
# scale bar position in sub-characters width
done=$(bc <<<"scale=0; $current * $bar_size / $total")
# Generate mid and (rounded down) todo from done
((mid = done % div))
((todo = bar_size - done))
# scale to character width
((done /= div))
((todo /= div))
bar_done=$(repeat "$done_char" "$done")
if ((mid == 0)); then
bar_mid=
else
bar_mid=${BAR_CHARS:mid:1}
fi
bar_todo=$(repeat "$todo_char" "$todo")
# calculate the progress in percentage
percent=$(bc <<<"scale=$BAR_SCALE; 100 * $current / $total")
echo -n "${bar_done}${bar_mid}${bar_todo}"
fi
tput sgr0
echo -n "] ${percent}%"
fi
}
# Test it
MAX=1000
for i in $(seq $MAX); do
progress "\rProgress: " "-en" "$i" "${MAX}"
done
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment