X-mailer: m, by Cameron Simpson Subject: Re: BASH scripting question References: To: redhat-list@redhat.com Cc: Alexei Nefediev From: Cameron Simpson Reply-to: cs@zip.com.au Errors-to: cs@zip.com.au Return-receipt-to: cs@zip.com.au Organization: Canon Information Systems Research Australia, Sydney, Oz On 24 Oct 1998, in message Alexei Nefediev wrote: | what should I do to learn my own script to understand switches and to | report about its usage when started without arguments? Step 1: Never write for "bash" (or the other dialects like zsh ksh etc) if you can write for plain vanilla Bourne shell (sh). Step 2: This is what I do: 0: Opening comment, usually quite short: #!/bin/sh # # Blah blah blah. - Cameron Simpson 27oct98 # a: Stash the basename of the program in a variable. I use $cmd; $prog and $progname are also common choices: cmd=`basename "$0"` b: Set defaults for options: time=1 # default time delay noaction= # no noaction verbose= # silent [ -t 1 ] && verbose=1 # unless we're interactive c: Define a usage message. Very near the top, so it doubles as documentation for someone reading the script source. Notice how we can mention the defaults in the message this way: usage="Usage: $cmd [-n] [-s] [-t time] [-v] files... -n No action. Just report what action would normally occur. -s Silent. -t time Pause for time seconds between files (default: $time). -v Verbose." Also notice the notation: word Required. [word] Optional. word... At least one required: one or more. [word...] Zero or more. {-s|-v} Alternatives: use -s or -v, not both. This notation is common to manual entries and usage messages and makes the simple aspects of use readily apparent. d: Parse options. Since most need a shift we do the usual one after the "esac". For options with an argument (-t) we add an extra shift in that line. Notice now the error message includes both the program name and the errant option, and goes to stderr. Always take this care - it will repay you and your users many times over in the future. badopts= while : do case $1 in -n) noaction=1 ;; # no action -s) verbose= ;; # turn verbose off -t) time=$2; shift ;; # set time -v) verbose=1 ;; # turn verbose on --) shift; break ;; # force end of option parsing -?*) echo "$cmd: unrecognised option: $1" >&2 badopts=1 # remember ;; *) break ;; # not an option - time to stop esac shift done # make sure they supply at least one file [ $# = 0 ] && { echo "$cmd: missing files" >&2; badopts=1; } # If anything went wrong, report correct usage. # # Notice that we do this really late, so as to make as many # complaints about problems as possible - nothing's as annoying # as having to fix some mistake and _only_then_ be told about the # next one. # # Also notice that we never ever proceed and run the program if the # arguments are in any way bad. # Bad arguments suggest that either the user didn't say what they meant # or possibly that they didn't even invoke the right program! # In either case proceeding might well do something horribly # different to the user's intent. So don't. # # Notice the non-zero exit status. # _All_ UNIX programs exit with zero on "success" and non-zero # on error. Make sure yours do too. # [ $badopts ] && { echo "$usage" >&2; exit 2; } e: The main program follows after that. For example: for file do echo "file=$file" done Cheers, -- Cameron Simpson, DoD#743 cs@zip.com.au http://www.zip.com.au/~cs/ THE LOST WORLD is based on (so loosely as to re-define "based on" as "with the same title as") Michael Crichton's sequel novel, which introduced us to a second island where dinosaurs were being genetically engineered. - Scott Renshaw on _Jurassic_Park_'s sequel