‘bar’ - ‘cat’ with ASCII progress bar

This is a small shell script intended to be used in
portable Unix install scripts for showing progress bars.

The overall goal is to write a minimally complex shell script
(thus a program that needs no compilation) that is as robust
as possible to work on as many Bourne shells and operating
systems as possible, and that implements ‘cat’ with an
ASCII progress bar and some other nifty features.

This is pure Bourne shell code.
(For sh, ash, ksh, zsh,
bash, ...)

The script is mainly intended to be used in portable install
scripts, where you can use the body of the script.

Documentation

Options Overview

For the shell script, features are usually passed on the command line,
and for the shell function (but also for the script), features are
passed as exported environment variables. The following tables gives
an overview of the features

Cmd. Line

Env. Var

Description

-o FILE

use shell redirection

Redirects output to a file.

-n

BAR_CLEAR=1

After termination, clear the line with the bar instead of leaving a
full bar on the console.

-p

BAR_PERC=0

Hides the percentage display.

-E

BAR_ETA=0

Hides the estimated time of arrival (ETA) display.

-t

BAR_TRACE=1

Shows the current file (trace mode).

-T WIDTH

BAR_TRACE_WIDTH=WIDTH

Sets the number of characters reserved for the current file display.
If not set, the default is 10.

-q

BAR_OK=0

Hides the bar completely, and reverts to the plain behaviour of cat.

-c CMD

BAR_CMD=CMD

For each file, pipe the contents into CMD. The command
is evaluated in the shell, you have access to the internal variables
of the script. Currently, the most interesting variable is bar_file
which contains the name of the current file as given on the command line,
i.e., without the additional ending set by BAR_EXT.

-e EXT

BAR_EXT=EXT

Sets EXT as an additional file extension to be appended
to each given file.

-d DIR

BAR_DIR=DIR

Sets DIR to be prefixed to each given file. Typically
used for prepending directories to each file, in which case the
argument must end in a slash.

-b SIZE

BAR_BS=SIZE

Sets the maximal block size to use for dd. By default, this
is 1048567 (= 1 MB). The command line option accepts suffixes:
k for kilobytes and M for megabytes. The environment
variable must be specified in bytes.

-s SIZE

BAR_SIZE=SIZE

Sets the expected number of bytes expected to be processed. Under
no circumstances, this may be smaller than the amount of bytes
read, as the script might process less bytes of data then (but this
is also not good for restricting the data flow to an exact number
of bytes, since the internal counting is heuristical: the script
will cut the stream at some unpredictable point after the given
amount of bytes).

Like -b, the command line accepts k
and M suffixes, but only when the result is smaller than
the numbers expr can handle.

Without using suffixes, i.e., in bytes, you may specify
any amount, even larger ones than expr can handle.

-w WIDTH

BAR_WIDTH=WIDTH

Sets the bar width to WIDTH characters. The script
tries to find a default value by using the environment variable
COLUMNS. If it is not set, the default is 76.

-0 CHAR

BAR_C0=CHAR

Sets the character displayed for work yet to be done.

-1 CHAR

BAR_C1=CHAR

Sets the character displayed for work already done.

-[ CHAR

BAR_A=CHAR

Sets the first character displayed in the bar (may be empty).

-] CHAR

BAR_B=CHAR

Sets the last character displayed in the bar (may be empty).

-V

Prints the version number and exits.

-D

Tries to dump the bar_cat() shell function,
i.e. everything but the command line interface.
The output can be included in your own scripts.
This options strips comments, empty lines, and leading white
space on all lines to make the result small.

Some features may be removed completely from the dumped shell code
by specifying the corresponding options before -D. These
are: -t (trace), -p (percentage), -E (ETA) and
-L (large file support). (-L only has an effect with
-D.)

-D-

Same as -D, but only dumps the function body.

--

Last option: only file names follow

Input Files

In the comment line, after the options, the input files follow.
The shell function bar_cat is invoked with that list of
files.

Note: If the list of files you provide to bar_cat is
empty, nothing is read. To explicitly state that stdin is
to be read, use the special file name /dev/stdin.

The command line interface invoked with no file names will
also read from stdin.

Bugs

\ cannot be used as a character in the bar, since printf
will interpret it. (And on systems that lack printf, but
support echo 'nonewline\c', echo is likely to also
interpret \ with other escape sequences.)

When neither ‘printf’ nor ‘echo -n’ is found to work, switch
off bar display just like for missing ‘dd’ or ‘grep’ -- currently,
the normal loop is executed without showing anything. This is
actually correct, but quite stupid.

Version 1.2 (Stable; Bug Fixes)

Bug fix: eliminate use of test "${VAR-unset}" = unset in favour
of test -z "${VAR}" (those are not the same, but the latter is good
in this script). And get rid of ${VAR-VALUE} altogether.

Bug fix: redirect output of 'ls ...' to /dev/null in order not to
interfere with displaying the bar.

Bug fix: -p was a unary instead of a nullary option

Cancelled Bug fix: check whether echo interprets backslashes by default,
and if so, try to disable it using -E. Cancelled, since checking
whether -E works is a major source of complexity. We just have to
live with echo that interprets backslashes.

Bug fix: print additional carriage return at beginning of every line in case
echo needs no options (in which case it may still print a space).

Bug fix: revert to plain cat behaviour if echo cannot be
used without newline.

Bug fix: before using -n with echo, try whether it accepts it
without signalling an error.

Bug fix: if any file is not found or is not a regular file,
we currently must switch off the bar display, since the total byte
amount might be totally wrong.

Bug fix: use pattern matching to divide large numbers (=file sizes)
by powers of ten so we can use expr on them.

Bug fix: carefully check and fix all computations to be more precise.

Bug fix: BAR_EXT (and the new BAR_DIR) did not work and lead to
switching off the bar.

Robustness: remove duplicate test -f in loop where it is
never reached and in the same way, remove superfluous check
for stdin.

Robustness: Most programs are checked fo in advance (expr, dd, grep, etc.) and
plain mode is activated if something is missing. The script tries to
never fail just because displaying the progress bar is not possible.