├── LICENSE ├── README.md ├── example.sh ├── other └── example.gif └── progress.sh /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Peter Goldsborough 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of 5 | this software and associated documentation files (the "Software"), to deal in 6 | the Software without restriction, including without limitation the rights to 7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 8 | the Software, and to permit persons to whom the Software is furnished to do so, 9 | subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # progress 2 | 3 | [![GitHub license](https://img.shields.io/github/license/mashape/apistatus.svg?style=flat-square)](http://goldsborough.mit-license.org) 4 | 5 | ``` 6 | _ _ _ __ _ __ _ __ __ ___ ___ 7 | ( '_`\ ( '__)/'_`\ /'_ `\( '__)/'__`\/',__)/',__) 8 | | (_) )| | ( (_) )( (_) || | ( ___/\__, \\__, \ 9 | | ,__/'(_) `\___/'`\__ |(_) `\____)(____/(____/ 10 | | | ( )_) | 11 | (_) \___/' 12 | ``` 13 | 14 | `progress`, the pluggable command line progress bar. 15 | 16 | ## Description 17 | 18 | `progress` is a lightweight, configurable script you can source into your own 19 | shell script to include a fancy progress bar informing your users about the 20 | progression of your program. You yourself decide what a unit of progress 21 | means and when progress begins or ends. 22 | 23 | ## Basic Usage 24 | 25 | A basic usage example may look something like this: 26 | 27 | ```shell 28 | #!/bin/bash 29 | PROGRESS_NUMBER_OF_STEPS=10 30 | source progress.sh 31 | 32 | for i in $(seq 10); do 33 | echo $i 34 | sleep .1 35 | progress_step 36 | done 37 | ``` 38 | 39 | Here, we defined the number of steps our program was going to make and then included the progress script in our script. This made one important function available: `progress_start`. You can call it whenever you want to increment your progress bar, and the script will add one unit to the progress bar. 40 | 41 | ![demo](https://raw.githubusercontent.com/goldsborough/progress/master/other/example.gif?token=AGIcm7AzP2_mzC7Kin7LGZ7sJOJoNdHEks5YZTH3wA%3D%3D) 42 | 43 | ## Advanced Usage 44 | 45 | `progress` is made to be very configurable. Here is a list of variables you can tweak, by setting them before you source the script: 46 | 47 | ##### `PROGRESS_WIDTH` 48 | 49 | How many characters the progress bar should be wide. The `PROGRESS_WIDTH` may be larger or smaller than the number of steps and the progress will adapt itself. Note that when the `PROGRESS_WIDTH` is not divisible by the `PROGRESS_NUMBER_OF_STEPS`, or the other way around, you *must* call `progress_end` instead of `progress_step` at the very end, to fill up the progress bar. 50 | 51 | ##### `PROGRESS_SYMBOL` 52 | 53 | The character to use for progress. It defaults to the unicode character `\u25AC` (▬). 54 | 55 | ##### `PROGRESS_FILL_SYMBOL` 56 | 57 | The character to use for progress not yet made. It defaults to the value of `PROGRESS_SYMBOL` (but with different default color). 58 | 59 | ##### `PROGRESS_FORMAT` 60 | 61 | A semi-colon-delimited list of UNIX terminal format codes to style the `PROGRESS_SYMBOL`, e.g. `1;31` for red and bold. 62 | 63 | ##### `PROGRESS_FILL_FORMAT` 64 | 65 | A semi-colon-delimited list of UNIX terminal format codes to style the `PROGRESS_FILL_SYMBOL`. 66 | 67 | ##### `PROGRESS_DEFER` 68 | 69 | Whether to start the progress bar immediately when sourced or wait until progress_start is called (which you don't have to call if you don't set this variable). The exact value does not matter, it just has to be defined to take effect. 70 | 71 | ##### `PROGRESS_INDICATOR_FORMAT` 72 | 73 | A semi-colon-delimited list of UNIX terminal format codes to use for the step indicator (`step/number of steps`). 74 | 75 | ##### `PROGRESS_PERCENT_FORMAT` 76 | 77 | A semi-colon-delimited list of UNIX terminal format codes to use for the percent value to the right of the progress bar. 78 | 79 | ##### `PROGRESS_STICKY` 80 | 81 | Whether or not to have the progress bar stay sticky on the top of the terminal when it overflows the terminal's number of lines. 82 | 83 | ##### `progress_line_number` 84 | 85 | `progress` exposes the internal variable `progress_line_number`, which you can modify yourself if you print more than one line of text in one step (`progress` assumes by default that one step = one line). You can also set the number of lines printed since the last step by passing that number to `progress_step` as an argument (it defaults to 1). 86 | 87 | ##### Formatting 88 | 89 | You can find a list of "UNIX terminal format codes" as mentioned above here: http://misc.flogisoft.com/bash/tip_colors_and_formatting. These codes allow you to change the foreground and background color, as well as make text bold or even hide something all together (for example if you don't want the percent, you can use format code 8 to hide it). 90 | 91 | ## LICENSE 92 | 93 | This project is released under the [MIT License](http://goldsborough.mit-license.org). For more information, see the LICENSE file. 94 | 95 | ## Authors 96 | 97 | [Peter Goldsborough](http://goldsborough.me) + [cat](https://goo.gl/IpUmJn) :heart: 98 | -------------------------------------------------------------------------------- /example.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | PROGRESS_STICKY=yes 4 | PROGRESS_WIDTH=80 5 | PROGRESS_NUMBER_OF_STEPS=${1:-10} 6 | source progress.sh 7 | 8 | for i in $(seq $PROGRESS_NUMBER_OF_STEPS); do 9 | echo $i 10 | sleep .05 11 | progress_step 12 | done 13 | -------------------------------------------------------------------------------- /other/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goldsborough/progress/5f15967ed78ce462726834227ab1b7b13a1a499b/other/example.gif -------------------------------------------------------------------------------- /progress.sh: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # _ _ _ __ _ __ _ __ __ ___ ___ 3 | # ( '_`\ ( '__)/'_`\ /'_ `\( '__)/'__`\/',__)/',__) 4 | # | (_) )| | ( (_) )( (_) || | ( ___/\__, \\__, \ 5 | # | ,__/'(_) `\___/'`\__ |(_) `\____)(____/(____/ 6 | # | | ( )_) | 7 | # (_) \___/' 8 | # 9 | # progress, the pluggable command line progress bar. 10 | # 11 | # progress is a lightweight, configurable script you can source into your own 12 | # shell script to include a fancy progress bar informing your users about the 13 | # progression of your program. You yourself decide what a unit of progress 14 | # means and when progress begins or ends 15 | # 16 | # A basic usage example may look something like this: 17 | # 18 | # #!/bin/bash 19 | # PROGRESS_NUMBER_OF_STEPS=10 20 | # source progress.sh 21 | # 22 | # for i in $(seq 10); do 23 | # echo $i 24 | # sleep .1 25 | # progress_step 26 | # done 27 | # 28 | # progress_end 29 | # 30 | # Here, we defined the number of steps our program was going to make and then 31 | # included the progress script in our script. This made two functions 32 | # available: progress_start and progress_end. You can call the former whenever 33 | # you want to increment your progress bar and must call the latter at the end 34 | # of your progress, under certain circumstances. 35 | # 36 | # progress is made to be very configurable. Here is a list of variables you can 37 | # tweak, by setting them before you source the script: 38 | # 39 | # * PROGRESS_WIDTH: How many characters the progress bar should be wide. 40 | # The PROGRESS_WIDTH may be larger or smaller than the number of steps and 41 | # the progress will adapt itself. Note that when the progress_width is not 42 | # divisible by the number_of_steps, or the other way around, you must call 43 | # progress_end to fill up the progress bar at the end of your program. 44 | # * PROGRESS_SYMBOL: The character to use for progress. 45 | # * PROGRESS_FILL_SYMBOL: The character to use for progress not yet made. 46 | # * PROGRESS_FORMAT: A semi-colon-delimited list of UNIX terminal format codes 47 | # to style the PROGRESS_SYMBOL. 48 | # * PROGRESS_FILL_FORMAT: A semi-colon-delimited list of UNIX terminal format 49 | # codes to style the PROGRESS_FILL_SYMBOL. 50 | # * PROGRESS_DEFER: Whether to start the progress bar immediately when sourced 51 | # or wait until progress_start is called (which you don't have to call if 52 | # you don't set this variable). The exact value does not matter, it just has 53 | # to be defined to take effect. 54 | # * PROGRESS_INDICATOR_FORMAT: A semi-colon-delimited list of UNIX terminal 55 | # format codes to use for the step indicator (step/number of steps). 56 | # * PROGRESS_PERCENT_FORMAT: A semi-colon-delimited list of UNIX terminal 57 | # format codes to use for the percent value to the right of the progress bar. 58 | # * PROGRESS_STICKY: Whether or not to have the progress bar stay sticky 59 | # on the top of the terminal when it overflows the terminal's number of 60 | # lines. 61 | # 62 | # You can find a list of "UNIX terminal format codes" here: 63 | # http://misc.flogisoft.com/bash/tip_colors_and_formatting. These codes allow 64 | # you to change the foreground and background color, as well as make text bold 65 | # or even hide something alltogether (for example if you don't want the 66 | # percent, you can use format code 8). 67 | # 68 | # Also, progress exposes the variable progress_line_number, which you can 69 | # modify yourself if you print more than one line of text in one step, for 70 | # example (progress assumes by default that one step = one line). You can 71 | # also set the number of lines printed since the last step by passing that 72 | # number to progress_step as an argument. 73 | ############################################################################### 74 | 75 | ############################################################################### 76 | # BASIC FUNCTIONS 77 | ############################################################################### 78 | 79 | # Keep all variables in the 'progress' namespace because 80 | # this script is intended to be sourced (to avoid collisions with 81 | # users' variables) 82 | 83 | function ceiling_divide { 84 | ((result=($1 + ($2 - 1))/$2)) 85 | echo $result 86 | } 87 | 88 | function string_of_length { 89 | # Space-separate a sequene of N numbers and 90 | # replace each number with the wanted character 91 | seq $1 | tr '\n' ' ' | perl -pe "s/[0-9]+ /$2/g" 92 | } 93 | 94 | function move_up { 95 | # The escape sequence \033[A moves the cursor lines up 96 | # The carriage return '\r' moves the cursor to the start of the line 97 | echo -en "\033[${1}A\r" 98 | } 99 | 100 | function move_down { 101 | # The escape sequence \033[B moves the cursor lines down 102 | # and the carriage return '\r' moves the cursor to the far left again (communism) 103 | echo -en "\033[${1}B\r" 104 | } 105 | 106 | function print_progress { 107 | if [ $1 -gt $2 ]; then 108 | return 1 109 | fi 110 | 111 | # The indicator (current_steps/total_steps) width is two times the total 112 | # number, since ultimately we'll want to print "(total/total)", plus 3 for 113 | # the parantheses and forward slash 114 | indicator_width=$(echo $2 | awk '{ print length($1) * 2 + 3}') 115 | 116 | # printf allows us to right justify the text according to the maximum width 117 | indicator=$(printf "%${indicator_width}s" "($1/$2)") 118 | indicator="\033[${progress_indicator_format}m${indicator}\033[0m" 119 | 120 | percent=$(echo "(100.0 * $1) / $2" | bc) 121 | percent="\033[${progress_percent_format}m[${percent}%]\033[0m" 122 | 123 | # PROGRESS in bold (usually displayed as bright formats) 124 | echo -en "\033[1mPROGRESS\033[0m: $indicator $3 $percent" 125 | } 126 | 127 | ############################################################################### 128 | # VARIABLES 129 | ############################################################################### 130 | 131 | if [ -z $PROGRESS_NUMBER_OF_STEPS ]; then 132 | echo -e "\033[31m[ERROR]\033[0m \$PROGRESS_NUMBER_OF_STEPS was not set!" 133 | exit -1 134 | fi 135 | 136 | # These here can be configured externally 137 | progress_number_of_steps=$PROGRESS_NUMBER_OF_STEPS 138 | progress_width=${PROGRESS_WIDTH:-$PROGRESS_NUMBER_OF_STEPS} 139 | progress_indicator_format=${PROGRESS_INDICATOR_FORMAT:-31} 140 | progress_percent_format=${PROGRESS_PERCENT_FORMAT:-35} 141 | 142 | # The symbol for actual progress made 143 | progress_symbol=${PROGRESS_SYMBOL:-'\xE2\x96\xAC'} 144 | progress_symbol=$(echo -en "$progress_symbol") 145 | 146 | # The escape code for the progresss format 147 | progress_format=${PROGRESS_FORMAT:-32} 148 | 149 | # The symbol for progress not yet made 150 | progress_fill_symbol=${PROGRESS_FILL_SYMBOL:-"$progress_symbol"} 151 | progress_fill_format=${PROGRESS_FILL_FORMAT:-0} 152 | 153 | # How many steps should equal an increment in one unit of progress 154 | # This value is important when the number of steps is greater than the width 155 | # because then it is not the case that one step = one extra bar of progress 156 | # but rather k steps will equal one bar of progress, with k > 1 157 | progress_divisor=$(ceiling_divide $progress_number_of_steps $progress_width) 158 | 159 | # The step size needs to be stored for the other extreme case, where the width 160 | # of the progress bar is greater (i.e. contains more units) than there are 161 | # steps. In that case, each step constitutes a greater number of units for the 162 | # progress bar. 163 | progress_step_size=$(ceiling_divide $progress_width $progress_number_of_steps) 164 | 165 | # One unit of progress (containing progress_step_size many characters) 166 | progress_unit=$(string_of_length $progress_step_size "$progress_symbol") 167 | 168 | # Throw in the escape codes. Note that the progress must be terminated with the 169 | # format escape of the filler, to restore its format after inserting the progress 170 | progress_unit=$(echo -en "\033[${progress_format}m$progress_unit\033[${progress_fill_format}m") 171 | 172 | # One unit of filler we replace with each unit of progress each time 173 | progress_fill_unit=$(string_of_length $progress_step_size "$progress_fill_symbol") 174 | 175 | # The actual progress bar 176 | progress_line=$(string_of_length $progress_width "$progress_fill_symbol") 177 | progress_line="\033[${progress_fill_format}m${progress_line}\033[0m" 178 | 179 | # How many steps we have made so far (out of $number_of_steps many) 180 | # If the width is greater than the number of steps, we will have to 181 | # advance the progress_index by more than 1 on each progress_step. 182 | progress_step=0 183 | 184 | # How many lines have been printed so far 185 | progress_line_number=1 186 | progress_max_lines=$(tput lines) 187 | ((progress_max_lines = progress_max_lines - 2)) 188 | 189 | ############################################################################### 190 | # PROGRESS FUNCTIONS 191 | ############################################################################### 192 | 193 | function progress_step { 194 | 195 | # Don't overflow ... 196 | if [ -z $PROGRESS_STICKY ] && [ $progress_line_number -ge $progress_max_lines ]; then 197 | return 0 198 | elif [ $progress_step -gt $progress_number_of_steps ]; then 199 | return 0 200 | fi 201 | 202 | ((progress_step += 1)) 203 | ((remainder=progress_step % progress_divisor)) 204 | 205 | if [ $remainder -eq 0 ]; then 206 | # Replace one unit of the filler with one unit of progress 207 | progress_gsed_command="s/$progress_fill_unit/$progress_unit/" 208 | 209 | # If the fill symbol equals the progress symbol, we need to specify after 210 | # which match to start replacing, else we'll just match the first replacement 211 | # we made (since we'd be replacing e.g. xxxx with \033[31mx\033[0mxxx which 212 | # still contains x as the first text character, so next time we'd get 213 | # \033[31m\033[31mx\033[0m\033[0m instead of replacing the next fill character) 214 | if [ "$progress_fill_symbol" = "$progress_symbol" ]; then 215 | ((progress_index = progress_step / progress_divisor)) 216 | progress_gsed_command="${progress_gsed_command}${progress_index}" 217 | fi 218 | progress_line="$(echo -e "$progress_line" | sed "$progress_gsed_command")" 219 | fi 220 | 221 | # We must always increment on the last step 222 | if [ $progress_step -eq $progress_number_of_steps ]; then 223 | ((progress_line_number += ${1:-1})) 224 | # Dont' increment when we've reached the end of the terminal 225 | elif [ $progress_line_number -lt $progress_max_lines ]; then 226 | # If nothing is passed, we increment by one (default), else if it is 227 | # -1, we do nothing (don't increment), else (if it's nonzero) we increment 228 | # by the given amount. 229 | if [ -z $1 ]; then 230 | ((progress_line_number += 1)) 231 | elif [ $1 -ne -1 ]; then 232 | ((progress_line_number += $1)) 233 | fi 234 | fi 235 | 236 | # Go back to the beginning of the line 237 | move_up $progress_line_number 238 | print_progress $progress_step $progress_number_of_steps "$progress_line" 239 | move_down $progress_line_number 240 | } 241 | 242 | # At the end, we fill up the progress bar. This is to account for when the step 243 | # number and progress width are incompatible. This is the case when, for example, 244 | # the width is greater than the number of steps and they are not divisible 245 | function progress_end { 246 | if [ -z $PROGRESS_STICKY ] && [ $progress_line_number -ge $progress_max_lines ]; then 247 | return 0 248 | fi 249 | 250 | progress_line="$(echo -en "$progress_line" | perl -pe 's/$(echo $progress_fill_symbol)/'$progress_symbol'/g')" 251 | if [ $1 ]; then 252 | ((progress_line_number += $1)) 253 | fi 254 | move_up $progress_line_number 255 | print_progress $progress_number_of_steps $progress_number_of_steps "$progress_line" 256 | move_down $progress_line_number 257 | } 258 | 259 | function progress_start { 260 | print_progress $progress_step $progress_number_of_steps "$progress_line" 261 | echo "" 262 | } 263 | 264 | if [ -z $PROGRESS_DEFER ]; then 265 | progress_start 266 | fi 267 | --------------------------------------------------------------------------------