Bourne's getopts
sadly makes simple shell scripts more cluttered and verbose
A while back I wrote about how I wanted to use getopts
more in
my shell scripts in order to have proper
real option handling instead of faking it in bad ways. Recently I
was modifying a few simple scripts that took arguments, so I decided
to do the right thing and switch them from simple hacks to getopts
.
This worked, but what it showed me is that simple use of getopts
is
going to make my scripts annoyingly more verbose.
Imagine that I have a script that takes a single option that can
change its behavior, say '-f
' for 'build Go without also running
its native build tests'. In a simple crude script, this is handled
like so:
fast="" if [ "$1" = "-f" ]; then fast="y" fi
This lacks many niceties, but it's short and simple (and in some
cases you might just stick the actual extra things to do inside the
if
condition). The same version with getopts
winds up something
like this:
usage() { echo "usage: make-all.sh [-f]" 1>&2; exit 1; } o_fast= while getopts f opt; do case $opt in f) o_fast=y;; *) usage;; esac done; shift $(($OPTIND-1)); [[ $# != 0 ]] && usage
I've deliberately compacted some lines here in order to make this smaller. One could golf it a bit further, but there are limits to that (both for readability and just in Bourne syntax). And it's still clearly larger (and more complex) than the simple version.
(The actual simple version also uses --fast
instead of -f
, but
getopts
doesn't deal with GNU style long options at all; so much
for that.)
If I was writing big scripts with complicated argument handling,
this wouldn't matter; getopts
would be a clear improvement and
the code size would be much more comparable. But I have a lot of
little scripts that take one or two arguments and do very simple
things with command line options, and for those doing things the
right way is unavoidably a bunch more verbose.
(Abstracting this into a function that is then in a function library
that gets .
-included is not a solution because I want my little
scripts to be and remain standalone artifacts that I can just copy
around freely.)
The result of this is that I wish there was some sort of simple
setopts
builtin that basically did the simple case; take a set
of options, set standard variables for every option present, complain
about usage if necessary, and maybe check and complain if you told
it how many arguments your command takes. I would use that a bunch,
because about 90% of the time that is a great first stage for option
and argument handling in my scripts.
(Maybe I need to do a few additional checks for conflicting options if this is an advanced script.)
PS: I'm going to keep the getopts
usage in the scripts I've
converted and I'm going to try to keep on using it, even in simple
scripts. Maybe I'll get acclimatized eventually, and even if I don't
it's clearly the right thing to do. Although I really wish getopts
could deal with long options, because long options are much better
for reminding you what an infrequently used option might do.
|
|