I would like to share this little shell function that I wrote to spice up my shell scripts. It is a simple progress bar that you can launch for a number of seconds, to get an idea of how long there is still to wait.
It uses partial Unicode blocks to achieve subcharacter precision.
Usage
Include the function in your code, or source the file
$ source progress_bar.sh $ progress_bar 60 # 60 seconds │█████████████████████████████████████████████████████████▌ │ 62%
You can use time on a long task to get the duration, and then
$ time ./compile.sh # gives 300 seconds $ ./compile.sh &>/dev/null & progress_bar 300 │███████████████████████████████ │ 31%
Installation
Clone the code
git clone https://github.com/nachoparker/progress_bar.sh
Include the function in your code, or source the file.
You can also add it to your .zshrc or .bashrc to use it as any other command.
cat progress_bar.sh >> ~/.bashrc cat progress_bar.sh >> ~/.zshrc
It requires a terminal session with unicode locales, for instance you might have in your .zshrc
export LC_ALL=en_US.UTF-8 export LANG=en_US.UTF-8 export LANGUAGE=en_US.UTF-8
Configuration
You can play around with the INT parameter for more smoothness.
Code
#!/bin/bash # Show a progress bar for $1 seconds # # Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com> # GPL licensed (see end of file) * Use at your own risk! # # Example: progress_bar 60 # progress_bar() { local DURATION=$1 local INT=0.25 # refresh interval local TIME=0 local CURLEN=0 local SECS=0 local FRACTION=0 local FB=2588 # full block trap "echo -e $(tput cnorm); trap - SIGINT; return" SIGINT echo -ne "$(tput civis)\r$(tput el)│" # clean line local START=$( date +%s%N ) while [ $SECS -lt $DURATION ]; do local COLS=$( tput cols ) # main bar local L=$( bc -l <<< "( ( $COLS - 5 ) * $TIME ) / ($DURATION-$INT)" | awk '{ printf "%f", $0 }' ) local N=$( bc -l <<< $L | awk '{ printf "%d", $0 }' ) [ $FRACTION -ne 0 ] && echo -ne "$( tput cub 1 )" # erase partial block if [ $N -gt $CURLEN ]; then for i in $( seq 1 $(( N - CURLEN )) ); do echo -ne \\u$FB done CURLEN=$N fi # partial block adjustment FRACTION=$( bc -l <<< "( $L - $N ) * 8" | awk '{ printf "%.0f", $0 }' ) if [ $FRACTION -ne 0 ]; then local PB=$( printf %x $(( 0x258F - FRACTION + 1 )) ) echo -ne \\u$PB fi # percentage progress local PROGRESS=$( bc -l <<< "( 100 * $TIME ) / ($DURATION-$INT)" | awk '{ printf "%.0f", $0 }' ) echo -ne "$( tput sc )" # save pos echo -ne "\r$( tput cuf $(( COLS - 6 )) )" # move cur echo -ne "│ $PROGRESS%" echo -ne "$( tput rc )" # restore pos TIME=$( bc -l <<< "$TIME + $INT" | awk '{ printf "%f", $0 }' ) SECS=$( bc -l <<< $TIME | awk '{ printf "%d", $0 }' ) # take into account loop execution time local END=$( date +%s%N ) local DELTA=$( bc -l <<< "$INT - ( $END - $START )/1000000000" \ | awk '{ if ( $0 > 0 ) printf "%f", $0; else print "0" }' ) sleep $DELTA START=$( date +%s%N ) done echo $(tput cnorm) trap - SIGINT } # License # # This script is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this script; if not, write to the # Free Software Foundation, Inc., 59 Temple Place, Suite 330, # Boston, MA 02111-1307 USA
This is great. I’m a little new to shell scripting so I have a newbie question: how would I incorporate this into a function? Any chance you could point me to a basic example so I can experiment with this?
function progress_bar () {
echo “YOUR CODE GOES HERE INSTEAD OF THE ECHO”
}
You don’t actually need to say “function” in BASH. The following will do:
progress_bar () {
echo “YOUR CODE GOES HERE INSTEAD OF THE ECHO”
}