This is a little tutorial that I found in my search to learn how to use getopt
(mind: not getopts
, which is a completely different thing). I want to share it here because I find it refreshingly to the point. Just the main code block already tells almost the whole story:
#!/bin/bash
# Set some default values:
ALPHA=unset
BETA=unset
CHARLIE=unset
DELTA=unset
usage()
{
echo "Usage: alphabet [ -a | --alpha ] [ -b | --beta ]
[ -c | --charlie CHARLIE ]
[ -d | --delta DELTA ] filename(s)"
exit 2
}
PARSED_ARGUMENTS=$(getopt -a -n alphabet -o abc:d: --long alpha,bravo,charlie:,delta: -- "$@")
VALID_ARGUMENTS=$?
if [ "$VALID_ARGUMENTS" != "0" ]; then
usage
fi
echo "PARSED_ARGUMENTS is $PARSED_ARGUMENTS"
eval set -- "$PARSED_ARGUMENTS"
while :
do
case "$1" in
-a | --alpha) ALPHA=1 ; shift ;;
-b | --beta) BETA=1 ; shift ;;
-c | --charlie) CHARLIE="$2" ; shift 2 ;;
-d | --delta) DELTA="$2" ; shift 2 ;;
# -- means the end of the arguments; drop this, and break out of the while loop
--) shift; break ;;
# If invalid options were passed, then getopt should have reported an error,
# which we checked as VALID_ARGUMENTS when getopt was called...
*) echo "Unexpected option: $1 - this should not happen."
usage ;;
esac
done
echo "ALPHA : $ALPHA"
echo "BETA : $BETA "
echo "CHARLIE : $CHARLIE"
echo "DELTA : $DELTA"
echo "Parameters remaining are: $@"
Just be sure to correct the inadvertent mixing of beta
and bravo
.
If you find yourself needing this, the correct thing to do is to stop writing that shell scripts and switch to a proper language.
While I agree with you, I think it’s a bit unkind to reply in this way. Sometimes bash is all you have, and it’s interesting to learn about tools even if you’re unlikely to use them.
I’ve got one from stackoverflow i tidied up and expanded, that handles long options as well, but you really should learn Python instead. Talking from experience; even with a state machine approach and helpful little functions and debug helpers, juggling so much input is hard in shell.
Well, you’re warned now and here it is:
tool_name="tool" tool_descr="tool does tool things" printhelp() { printf '%s\nSyntax: %s [options]...\n%s\n' "$tool_descr" "$tool_name" "$tool_args" } bool() { [ -n "$OPTARG" ] && error "--${OPT} accepts no parameters" 7; } # cli-parser #-------------------------------------------------------------- tool_args=' -s, --stuff stuff to do -o, --other other stuff to do -V, --verbose Tell what i do -v, --version Print version of this tool and exit -h, --help This help text ' while getopts "vVhbs:o:-:" OPT; do # support long options: https://stackoverflow.com/a/28466267/519360 if [ "$OPT" = "-" ]; then # long option: reformulate OPT and OPTARG OPT="${OPTARG%%=*}" # extract long option name OPTARG="${OPTARG#"$OPT"}" # extract long option argument (may be empty) OPTARG="${OPTARG#=}" # if long option argument, remove assigning `=` fi case "$OPT" in s | stuff ) arg_stuff="$OPTARG" ;; o | other ) arg_other="$OPTARG" ;; V | verbose ) bool; verbose=true ;; v | version ) bool; printversion; exit 0 ;; h | help ) printhelp; exit 0 ;; ??* ) error "Illegal option --$OPT" 22 # bad long option ;; : ) exit 2 # missing parameter (error reported via getopts) ;; ? ) exit 22 # bad short option (error reported via getopts) esac done [ $OPTIND -eq 1 ] && \ if { [ -e "$1" ] && [ $# -gt 0 ]; } # check for lazy file argument then lazy_arg="$1" else printhelp && exit 0 fi shift $((OPTIND-1)) # remove parsed options and args from $@ list
The article mentions “GNU getopt” but as far as I know GNU doesn’t have a
getopt
utility; the version on most Linux OSes comes from util-linux. (Perhaps the author is confusing it with the C function with the same name.)Note that other
getopt
implementations have different features and some are simply broken. For example, BSDgetopt
doesn’t support long options and comes with this known bug:Arguments containing whitespace or embedded shell metacharacters generally will not survive intact; this looks easy to fix but isn’t.
For cross-platform scripts it’s probably best to use the
getopts
shell builtin instead, the downside being it only supports fairly basic (POSIX) syntax even on Bash.I still think my favorite shell, NuShell, handles this the best:
def alphabet [ --alpha (-a) --charlie (-c): string # comments on these lines are parsed and used for automatically generated --help flag --delta: int ...filenames: string ] { echo \$alpha }"
So much less boilerplate
There is also the manual way, I am not saying it’s perfect but sometimes it offers better alternative than getopt.
https://gist.github.com/dgoguerra/9206418