]>
Tony Duckles's Git Repositories (git.nynim.org) - dotfiles.git/blob - bin/bar
   4 # 'cat' with ASCII progress bar 
   9 #   'bar' works just like 'cat', but shows a progress bar in ASCII art on stderr. 
  10 #   The script's main function is meant to be usable in any Bourne shell to be 
  11 #   suitable for install scripts without the need for any additional tool. 
  13 # Shell Script Usage: bar [options] [files] 
  21 #     : bar mypack.tar.bz2 | tar xjpf - 
  23 #   Individual pipe for each file: 
  25 #     : bar -c 'tar xjpf -' mypack1.tar.bz2 mypack2.tar.bz2 
  27 #   Individual pipe, using ${bar_file} variable: 
  29 #     : bar -c 'echo ${bar_file}: ; gzip -dc | tar tvf -' \ 
  31 #     :     file1 file2 file3 file4 file5 \ 
  32 #     :         > package-list.txt 
  34 ##################################################### 
  35 # Programs and shell commands: 
  37 # Required (otherwise this fails): 
  39 #    if, then, else, fi, expr, test, cat, eval, exec 
  58 # Optional (otherwise this does not show the bar): 
  60 #    grep, dd, echo, ls, sed, cut 
  63 #        must output the file size at fifth position. 
  65 # The command line interface also uses: 
  70 ####>-SCHNIPP-<######################################################## 
  73    # Use this shell function in your own install scripts. 
  75    ##################################################### 
  78    # Width of the bar (in ten characters).  The default is 76 characters. 
  79    test -z "${BAR_WIDTH}" && test -n "${COLUMNS}" && BAR_WIDTH
=${COLUMNS} 
  82    ( expr "${BAR_WIDTH}" + 0 >/dev
/null 
2>&1 ) || BAR_WIDTH
=0 
  83    BAR_WIDTH
=`expr ${BAR_WIDTH} + 0` || BAR_WIDTH
=0 
  84    test "x${BAR_WIDTH}" = x0 
&& BAR_WIDTH
=76 
  86    # Maximal block size to use for dd. 
  87    test -n "${BAR_BS}" || BAR_BS
=1048567 
  90    # Whether to show a percentage. 
  91    test -n "${BAR_PERC}" || BAR_PERC
=1 
  95    # Whether to show estimated time of arrival (ETA). 
  96    test -n "${BAR_ETA}" || BAR_ETA
=1 
  99    # Width of the trace display: 
 101    test -n "${BAR_TRACE_WIDTH}" || BAR_TRACE_WIDTH
=10 
 104    # The command to execute for every given file.  Each file 
 105    # is piped into this command individually.  By default, the 
 106    # files are simply dumped to stdout. 
 107    test -n "${BAR_CMD}" || BAR_CMD
=cat 
 109    # The characters to be used in the bar 
 110    test -n "${BAR_L}"  || BAR_L
='[' 
 111    test -n "${BAR_R}"  || BAR_R
=']' 
 112    test -n "${BAR_C0}" || BAR_C0
='.' 
 113    test -n "${BAR_C1}" || BAR_C1
='=' 
 115    # Additional extension to add to each file: 
 118    # Whether to clear bar after termination.  Otherwise keep the full bar. 
 119    #BAR_CLEAR=${BAR_CLEAR-0} 
 121    # Unless switched off by user, use the bar by default: 
 122    test -n "${BAR_OK}" || BAR_OK
=1 
 124    ##################################################### 
 125    BAR_WIDTH
=`expr ${BAR_WIDTH} - 3` 
 129    if test "x${BAR_TRACE}" = x1
 
 131        BAR_WIDTH
=`expr ${BAR_WIDTH} - ${BAR_TRACE_WIDTH}` 
 132        bar_lauf
=${BAR_TRACE_WIDTH} 
 135        while test "${bar_lauf}" -gt 1 
 137            bar_t_space
="${bar_t_space} " 
 138            bar_t_dot
="${bar_t_dot}." 
 139            bar_lauf
=`expr ${bar_lauf} - 1` 
 141        bar_trace
="${bar_t_space} " 
 148    ( expr 1 + ${SECONDS} >/dev
/null 
2>&1 ) || BAR_ETA
=0 
 149    if test "x${BAR_ETA}" = x1
 
 151        BAR_GET_TIME
='( echo ${SECONDS} )' 
 152        BAR_WIDTH
=`expr ${BAR_WIDTH} - 6` 
 159    if test "x${BAR_PERC}" = x1
 
 161        BAR_WIDTH
=`expr ${BAR_WIDTH} - 5` 
 166    BAR_GET_SIZE
='( ls -l "${BAR_DIR}${bar_file}${BAR_EXT}" | sed "s@  *@ @g" | cut -d " " -f 5 ) 2>/dev/null' 
 170    ( ( echo a                   
) >/dev
/null 
2>&1 ) || BAR_OK
=0 
 171    ( ( echo a 
| dd bs
=2 count
=2 ) >/dev
/null 
2>&1 ) || BAR_OK
=0 
 172    ( ( echo a 
| grep a          
) >/dev
/null 
2>&1 ) || BAR_OK
=0 
 173    ( ( echo a 
| sed 's@  *@ @g' ) >/dev
/null 
2>&1 ) || BAR_OK
=0 
 174    ( ( echo a 
| cut 
-d ' ' -f 1 ) >/dev
/null 
2>&1 ) || BAR_OK
=0 
 177    test "${BAR_WIDTH}" -ge 4 || BAR_OK
=0 
 184    # Does echo accept -n without signalling an error? 
 185    if echo -n abc 
>/dev
/null 
2>&1 
 190    # Check how to print a line without newline: 
 191    if ( ( ${BAR_ECHO} "${BAR_E_C1}" abc 
; echo 1,2,3 ) | grep n 
) >/dev
/null 
2>&1 
 194        if ( ( ${BAR_ECHO} 'xyz\c' ; echo 1,2,3 ) | grep c 
) >/dev
/null 
2>&1 
 197            if ( ( printf 'ab%s' c 
; echo 1,2,3 ) | grep abc 
) >/dev
/null 
2>&1 
 213    # prepare initial bar: 
 215    if test "${BAR_OK}" = 1 
 219        while test `expr ${bar_lauf} + 5` -le "${BAR_WIDTH}" 
 221            bar_graph
="${bar_graph}${BAR_C0}${BAR_C0}${BAR_C0}${BAR_C0}${BAR_C0}" 
 222            bar_lauf
=`expr ${bar_lauf} + 5` 
 224        while test "${bar_lauf}" -lt "${BAR_WIDTH}" 
 226            bar_graph
="${bar_graph}${BAR_C0}" 
 227            bar_lauf
=`expr ${bar_lauf} + 1` 
 229        ${BAR_ECHO} "${BAR_E_C1}" "
${bar_trace}${bar_eta}${bar_perc}${BAR_L}${bar_graph}${BAR_R}
${BAR_E_C2}" 1>&2 
 233    # for shifting large numbers so that expr can handle them: 
 234    # Assume we can compute up to 2147483647, thus 9 arbitrary digits. 
 235    # We must be able to do + of two numbers of 9 digits length.  Ok. 
 237    ( ( test 1999999998 = `expr 999999999 + 999999999` ) >/dev
/null 
2>&1 ) || BAR_OK
=0 
 238    bar_large_num
="........." 
 245    if test -n "${BAR_SIZE}" 
 249        while expr "${bar_size}" : "${bar_large_num}" >/dev
/null 
2>&1 
 251            bar_div
="${bar_div}." 
 252            bar_numsuff
="${bar_numsuff}0" 
 253            bar_size
=`expr "${bar_size}" : '\(.*\).$'` 
 256        BAR_GET_SIZE
="echo '${BAR_SIZE}'" 
 261            if test -f "${BAR_DIR}${bar_file}${BAR_EXT}" 
 263                bar_size1
=`eval "${BAR_GET_SIZE}"` 
 266                # divide and upround by pattern matching: 
 267                if test -n "${bar_div}" 
 269                    bar_size1
=`expr "${bar_size1}" : '\(.*\)'${bar_div}'$'` || bar_size1
=0 
 272                # adjust if still too large: 
 273                while expr "${bar_size1}" : "${bar_large_num}" >/dev
/null 
2>&1 
 275                    bar_div
="${bar_div}." 
 276                    bar_numsuff
="${bar_numsuff}0" 
 277                    bar_size1
=`expr "${bar_size1}" : '\(.*\).$'` 
 278                    bar_size
=`expr "${bar_size}" : '\(.*\).$'` || bar_size
=0 
 281                # upround if necessary: 
 282                if test -n "${bar_div}" 
 284                    bar_size1
=`expr "${bar_size1}" + 1` 
 289                bar_size
=`expr ${bar_size} + ${bar_size1}` 
 292                # adjust if still too large: 
 293                while expr "${bar_size}" : "${bar_large_num}" >/dev
/null 
2>&1 
 295                    bar_div
="${bar_div}." 
 296                    bar_numsuff
="${bar_numsuff}0" 
 297                    bar_size
=`expr "${bar_size}" : '\(.*\).$'` 
 306    bar_quad
=`expr ${BAR_WIDTH} '*' ${BAR_WIDTH}` 
 307    test "${bar_size}" -gt "${bar_quad}" || BAR_OK
=0 
 309    if test "${BAR_OK}" = 0 
 311        # For some reason, we cannot display the bar.  Thus plain operation: 
 314            if test "${bar_file}" = "/dev/stdin" 
 318                eval "${BAR_CMD}" < "${BAR_DIR}${bar_file}${BAR_EXT}" 
 322        # Compute wanted bytes per step: 
 323        bar_want_bps
=`expr ${bar_size} + ${BAR_WIDTH}` 
 324        bar_want_bps
=`expr ${bar_want_bps} - 1` 
 325        bar_want_bps
=`expr ${bar_want_bps} / ${BAR_WIDTH}` 
 327        # Compute block count per step to keep within maximum block size: 
 329        if test "${bar_want_bps}" -gt "${BAR_BS}" 
 331            bar_count
=`expr ${bar_want_bps} + ${BAR_BS}` 
 332            bar_count
=`expr ${bar_count} - 1` 
 333            bar_count
=`expr ${bar_count} / ${BAR_BS}` 
 336        # Compute block size for given count: 
 337        bar_wc
=`expr ${BAR_WIDTH} '*' ${bar_count}` 
 339        bar_bs
=`expr ${bar_size} + ${bar_wc}` 
 340        bar_bs
=`expr ${bar_bs} - 1` 
 341        bar_bs
=`expr ${bar_bs} / ${bar_wc}` 
 343        # Compute bs * count, the bytes per step: 
 344        bar_bps
=`expr ${bar_bs} '*' ${bar_count}` 
 346        # Compute bytes per hundredth: 
 347        bar_bph
=`expr ${bar_size} + 99` 
 348        bar_bph
=`expr ${bar_bph} / 100` 
 355        bar_t0
=`eval "${BAR_GET_TIME}" 2>/dev/null` || bar_t0
=0 
 359            if test "x${BAR_TRACE}" = x1
 
 361                bar_trace
=`expr "${bar_file}" : '.*/\([^/][^/]*\)$'` || bar_trace
="${bar_file}" 
 362                bar_trace
=`expr "${bar_trace}${bar_t_space}" : '\('${bar_t_dot}'\)'` 
 363                bar_trace
="${bar_trace} " 
 366            # Initial character position in bar for file: 
 367            bar_char
=`expr ${bar_pos} / ${bar_want_bps}` || bar_char
=0 
 368            while test "${bar_char}" -gt `expr ${bar_cur_char} + 4` 
 370                bar_graph
="${bar_graph}${BAR_C1}${BAR_C1}${BAR_C1}${BAR_C1}${BAR_C1}" 
 371                bar_cur_char
=`expr ${bar_cur_char} + 5` 
 373            while test "${bar_char}" -gt "${bar_cur_char}" 
 375                bar_graph
="${bar_graph}${BAR_C1}" 
 376                bar_cur_char
=`expr ${bar_cur_char} + 1` 
 379            # Get file size.  This must work now (we checked with test -f before). 
 380            bar_size1
=`eval "${BAR_GET_SIZE}" 2>/dev/null` || bar_size1
=0 
 383            # Divide and upround by pattern matching: 
 384            if test -n "${bar_div}" 
 386                bar_size1
=`expr "${bar_size1}" : '\(.*\)'${bar_div}'$'` || bar_size1
=0 
 387                bar_size1
=`expr "${bar_size1}" + 1` 
 395                exec 5<"${BAR_DIR}${bar_file}${BAR_EXT}" 
 396                while test "${bar_total}" -lt "${bar_size1}" 
 398                    dd bs
="${bar_bs}" count
="${bar_count}${bar_numsuff}" <&5 >&6 2>/dev
/null
 
 399                    bar_total
=`expr ${bar_total} + ${bar_bps}` 
 400                    if test "${bar_total}" -gt "${bar_size1}" 
 402                        bar_total
="${bar_size1}" 
 404                    bar_pos1
=`expr ${bar_pos} + ${bar_total}` 
 405                    bar_proz
=`expr ${bar_pos1} / ${bar_bph}` || bar_proz
=0 
 407                    if test "x${BAR_PERC}" = x1
 
 409                        bar_perc
="  ${bar_proz}% " 
 410                        bar_perc
=`expr "${bar_perc}" : '.*\(.....\)$'` 
 414                    if test "x${BAR_ETA}" = x1
 
 416                        bar_diff
=`eval "${BAR_GET_TIME}" 2>/dev/null` || bar_diff
=0 
 417                        bar_diff
=`expr ${bar_diff} - ${bar_t0} 2>/dev/null` || bar_diff
=0 
 418                        bar_100p
=`expr 100 - ${bar_proz}` || bar_100p
=0 
 419                        bar_diff
=`expr ${bar_diff} '*' ${bar_100p}` || bar_diff
=0 
 420                        bar_diff
=`expr ${bar_diff} + ${bar_proz}` || bar_diff
=0 
 421                        bar_diff
=`expr ${bar_diff} - 1` || bar_diff
=0 
 422                        bar_diff
=`expr ${bar_diff} / ${bar_proz} 2>/dev/null` || bar_diff
=0 
 423                        if test "${bar_diff}" -gt 0 
 426                            if test "${bar_diff}" -gt 2700 
 429                                bar_diff
=`expr ${bar_diff} / 60` 
 431                            bar_diff_h
=`expr ${bar_diff} / 60` || bar_diff_h
=0 
 432                            if test "${bar_diff_h}" -gt 99 
 434                                bar_eta
="     ${bar_diff_h}${bar_t_unit} " 
 436                                bar_diff_hi
=`expr ${bar_diff_h} '*' 60` || bar_diff_hi
=0 
 437                                bar_diff
=`expr ${bar_diff} - ${bar_diff_hi}` || bar_diff
=0 
 438                                bar_diff
=`expr "00${bar_diff}" : '.*\(..\)$'` 
 439                                bar_eta
="     ${bar_diff_h}${bar_t_unit}${bar_diff} " 
 441                            bar_eta
=`expr "${bar_eta}" : '.*\(......\)$'` 
 446                    bar_char
=`expr ${bar_pos1} / ${bar_want_bps}` || bar_char
=0 
 447                    while test "${bar_char}" -gt "${bar_cur_char}" 
 449                        bar_graph
="${bar_graph}${BAR_C1}" 
 450                        ${BAR_ECHO} "${BAR_E_C1}" "
${bar_trace}${bar_eta}${bar_perc}${bar_graph}${BAR_E_C2}" 1>&2 
 451                        bar_cur_char
=`expr ${bar_cur_char} + 1` 
 454            ) | eval "${BAR_CMD}" 
 455            bar_pos
=`expr ${bar_pos} + ${bar_size1}` 
 457        # ${BAR_ECHO} "${BAR_E_C1}" "${BAR_R}${BAR_E_C2}" 1>&2 
 460    if test "${bar_shown}" = 1 
 463        test "x${BAR_TRACE}" = x1 
&& bar_trace
="${bar_t_space} " 
 466        test "x${BAR_ETA}" = x1   
&& bar_eta
='      ' 
 468        if test "x${BAR_CLEAR}" = x1
 
 471            test "x${BAR_PERC}" = x1 
&& bar_perc
='     ' 
 475            while test `expr ${bar_lauf} + 5` -le "${BAR_WIDTH}" 
 477                bar_graph
="${bar_graph}     " 
 478                bar_lauf
=`expr ${bar_lauf} + 5` 
 480            while test "${bar_lauf}" -lt "${BAR_WIDTH}" 
 482                bar_graph
="${bar_graph} " 
 483                bar_lauf
=`expr ${bar_lauf} + 1` 
 485            ${BAR_ECHO} "${BAR_E_C1}" "
${bar_trace}${bar_eta}${bar_perc} ${bar_graph} 
${BAR_E_C2}" 1>&2 
 488            test "x${BAR_PERC}" = x1 
&& bar_perc
='100% ' 
 492            while test `expr ${bar_lauf} + 5` -le "${BAR_WIDTH}" 
 494                bar_graph
="${bar_graph}${BAR_C1}${BAR_C1}${BAR_C1}${BAR_C1}${BAR_C1}" 
 495                bar_lauf
=`expr ${bar_lauf} + 5` 
 497            while test "${bar_lauf}" -lt "${BAR_WIDTH}" 
 499                bar_graph
="${bar_graph}${BAR_C1}" 
 500                bar_lauf
=`expr ${bar_lauf} + 1` 
 502            ${BAR_ECHO} "${BAR_E_C1}" "
${bar_trace}${bar_eta}${bar_perc}${BAR_L}${bar_graph}${BAR_R}${BAR_E_C2}" 1>&2 
 507 ####>-SCHNAPP-<######################################################## 
 511 # Command line interface: 
 515        -o|-c|-w|-0|-1|-e|-d|-b|-s|-\
[\
]|-\
[|-\
]|-T) 
 518                echo "$0: Error: A non-empty argument was expected after $1" 1>&2 
 525        -o*|-c*|-w*|-0*|-1*|-e*|-d*|-b*|-T*) 
 526            BAR_ARG
=`expr "$1" : '\(-.\)'` 
 527            BAR_OPT
=`expr "$1" : '-.\(.*\)$'` 
 530        -h|-n|-p|-D|-D-|-q|-V|-t|-E|-L) 
 538        -*) echo "$0: Error: Unrecognized option: $1" 1>&2 
 547        -h)  echo 'Usage: bar [-n] [-p] [-q] [-o FILE] [-c CMD] [-s SIZE] [-b SIZE]' 
 548             echo '           [-w WIDTH] [-0/1/[/] CHAR] [-d DIR] [-e EXT] [Files]' 
 553             echo '     -h         displays help' 
 554             echo '     -o FILE    sets output file' 
 555             echo '     -c CMD     sets individual execution command' 
 556             echo '     -e EXT     append an extension to each file' 
 557             echo '     -d DIR     prepend this prefix to each file (a directory must end in /)' 
 558             echo '     -s SIZE    expected number of bytes.  Use for pipes.  This is a hint' 
 559             echo '                only that must be greater or equal to the amount actually' 
 560             echo '                processed.  Further, this only works for single files.' 
 561             echo '     -b SIZE    maximal block size (bytes) (default: 1048567)' 
 562             echo '     -w WIDTH   width in characters        (default: terminal width-3 or 76)' 
 563             echo '     -0 CHAR    character for empty bar    (default: .)' 
 564             echo '     -1 CHAR    character for full bar     (default: =)' 
 565             echo '     -[ CHAR    first character of bar     (default: [)' 
 566             echo '     -] CHAR    last  character of bar     (default: ])' 
 567             echo '     -n         clears bar after termination' 
 568             echo '     -t         traces (=displays) which file is processed' 
 569             echo '     -T WIDTH   no of characters reserved for the file display of -t' 
 570             echo '     -p         hides percentage' 
 571             echo '     -E         hides estimated time display' 
 572             echo '     -q         hides the whole bar, be quiet' 
 573             echo '     -D         tries to dump the bar_cat() shell function, then exit.' 
 574             echo '                Here, -t, -p, -E remove the corresponding feature completely.' 
 575             echo '                Further, -L removes large file support from the code.' 
 576             echo '     -D-        same as -D, but dumps the function body only' 
 577             echo '     -V         displays version number' 
 578             echo '     --         end of options: only file names follow' 
 584             BAR_AWK_0
="${BAR_AWK_0} /END  *LARGE/ {x=1} ;" 
 585             BAR_AWK_0
="${BAR_AWK_0} /BEGIN  *LARGE/ {x=0} ;" 
 588             BAR_AWK_0
="${BAR_AWK_0} /END  *TRACE/ {x=1} ;" 
 589             BAR_AWK_0
="${BAR_AWK_0} /BEGIN  *TRACE/ {x=0} ;" 
 591        -T)  BAR_TRACE_WIDTH
="${BAR_OPT}" 
 596             BAR_AWK_0
="${BAR_AWK_0} /END  *PERC/ {x=1} ;" 
 597             BAR_AWK_0
="${BAR_AWK_0} /BEGIN  *PERC/ {x=0} ;" 
 600             BAR_AWK_0
="${BAR_AWK_0} /END  *ETA/ {x=1} ;" 
 601             BAR_AWK_0
="${BAR_AWK_0} /BEGIN  *ETA/ {x=0} ;" 
 603        -V)  echo "bar v${BAR_VERSION}" 
 606        -D)  echo "BAR_VERSION=${BAR_VERSION}" 
 607             awk "${BAR_AWK_0}"'{sub(/ *#.*$/,"")} ; /^bar_cat/ {x=1} ; {sub(/^  */,"")} ; /./ {if(x)print} ; /^}/ {x=0}' "$0" 
 610        -D-) echo "BAR_VERSION=${BAR_VERSION}" 
 611             awk "${BAR_AWK_0}"'{sub(/ *#.*$/,"")} ; /^}/ {x=0} ; {sub(/^  */,"")} ; /./ {if(x)print} ; /^{/ {x=1}' "$0" 
 614        -o)  exec 1>"${BAR_OPT}" 
 616        -c)  BAR_CMD
="${BAR_OPT}" 
 618        -b)  BAR_BS
="${BAR_OPT}" 
 619             if BAR_RAW
=`expr "${BAR_BS}" : '\(.*\)k$'` 
 621                 BAR_BS
=`expr ${BAR_RAW} '*' 1024` 
 622             elif BAR_RAW
=`expr "${BAR_BS}" : '\(.*\)M$'` 
 624                 BAR_BS
=`expr ${BAR_RAW} '*' 1048567` 
 627        -s)  BAR_SIZE
="${BAR_OPT}" 
 628             if BAR_RAW
=`expr "${BAR_SIZE}" : '\(.*\)k$'` 
 630                 BAR_SIZE
=`expr ${BAR_RAW} '*' 1024` 
 631             elif BAR_RAW
=`expr "${BAR_SIZE}" : '\(.*\)M$'` 
 633                 BAR_SIZE
=`expr ${BAR_RAW} '*' 1048567` 
 637                 echo "Error: -s cannot be specified for multiple input files." 1>&2 
 641        -e)  BAR_EXT
="${BAR_OPT}" 
 643        -d)  BAR_DIR
="${BAR_OPT}" 
 645        -0)  BAR_C0
="${BAR_OPT}" 
 647        -1)  BAR_C1
="${BAR_OPT}" 
 649        -\
[) BAR_L
="${BAR_OPT}" 
 651        -\
]) BAR_R
="${BAR_OPT}" 
 657        -w)  BAR_WIDTH
="${BAR_OPT}" 
 662 # Invoke main function: