Skip to content

Instantly share code, notes, and snippets.

@bobpaul
Created March 20, 2018 18:24
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
  • Save bobpaul/ecd74cdf7681516703f20726431eaceb to your computer and use it in GitHub Desktop.
Save bobpaul/ecd74cdf7681516703f20726431eaceb to your computer and use it in GitHub Desktop.
An example showing how to use getopt
#!/usr/bin/env bash
# Time-stamp: <2017-04-27 09:57:21 kmodi>
# Time-stamp: <2018-03-20 12:58:02 bobpaul>
# derived from kmodi's gist: https://gist.github.com/kaushalmodi/74e9875d5ab0a2bc1010447f1bee5d0a
#
# Example of using getopt to parse command line options
# http://stackoverflow.com/a/29754866/1219634 Limitation: All the options
# starting with - have to be listed in --options/--longoptions, else getopt will
# error out.
# The downside is that if you intend to use this as a wrapper to some other program,
# arguments you want to pass on to that program must come after a -- argument.
# ex: mygrep --myoption mypositional -- -r 'options_for_real_grep' *
getopt --test 2> /dev/null
if [[ $? -ne 4 ]]; then
echo "GNU's enhanced getopt is required to run this script"
echo "You can usually find this in the util-linux package"
echo "On MacOS/OS X see homebrew's package: http://brewformulas.org/Gnu-getopt"
echo "For anyone else, build from source: http://frodo.looijaard.name/project/getopt"
exit 1
fi
#bash strict mode: see http://redsymbol.net/articles/unofficial-bash-strict-mode/ for info
set -euo pipefail
IFS=$'\n\t'
# Initialize variables
HELP=0
DEBUG=0
VERBOSE=0
declare -a EXTRA_ARGS
declare -a POSITIONAL
DISCARD_OPTS_AFTER_DOUBLEDASH=0 # 1=Discard, 0=Save opts after -- to ${EXTRA_ARGS}
echo "All pre-getopt arguments: $@"
# An option followed by a single colon ':' means that it *needs* an argument.
# An option followed by double colons '::' means that its argument is optional.
# See `man getopt'.
SHORT=-hDvo: # List all the short options
LONG=help,debug,verbose,outfile: # List all the long options
# - Temporarily store output to be able to check for errors.
# - Activate advanced mode getopt quoting e.g. via "--options".
# - Pass arguments only via -- "$@" to separate them correctly.
# - getopt auto-adds "--" at the end of ${PARSED}, which is then later set to
# "$@" using the set command.
PARSED=$(getopt --options ${SHORT} \
--longoptions ${LONG} \
--name "$0" \
-- "$@") #Pass all the args to this script to getopt
if [[ $? -ne 0 ]]; then
# e.g. $? == 1
# then getopt has complained about wrong arguments to stdout
exit 2
fi
# Use eval with "$PARSED" to properly handle the quoting
# The set command sets the list of arguments equal to ${PARSED}.
eval set -- "${PARSED}"
echo "Getopt parsed arguments: ${PARSED}"
echo "Effective arguments: $@"
echo "Num args: $#"
dashes=0 #flag to track if we've parsed '--'
while [[ $# -gt 0 ]]; do
echo "parsing arg: $1"
case "$1" in
-o|--outfile) shift
OUT_FILE="$1";;
-h|--help) HELP=1;;
-D|--debug) DEBUG=1;;
-v|--verbose) VERBOSE=1;;
--) dashes=1
if [[ ${DISCARD_OPTS_AFTER_DOUBLEDASH} -eq 1 ]]; then break; fi
;;
*) #store positional arguments until we reach the dashes, then store as extra
if [[ $dashes -eq 0 ]]; then POSITIONAL+=("$1");
else EXTRA_ARGS+=("$1"); fi
;;
esac
shift # Expose the next argument
done
set -- "${POSITIONAL[@]}"
echo ""
echo ""
echo "Parsed options:"
echo "help: ${HELP}, debug: ${DEBUG}, verbose: ${VERBOSE}, outfile: ${OUT_FILE:-}"
#restore positional arguments as $1, $2, etc
echo "Listing positional arguments:"
while [[ $# -gt 0 ]]; do
#here's where you can parse your positional arguments
echo "$1"
shift
done
echo "Extra arguments: (those after --)"
for i in ${!EXTRA_ARGS[@]}; do
#here's the extra args you can pass to a wrapped utility
echo "${EXTRA_ARGS[$i]}"
done
@bobpaul
Copy link
Author

bobpaul commented Mar 20, 2018

Example usage:

$ ./gnu_getopt_example.sh -h word1 -o 'filename with spaces' word2 word3 -- extra1 -l extra2\ with\ spaces words3
[...]
Parsed options:
help: 1, debug: 0, verbose: 0, outfile: filename with spaces
Listing positional arguments:
word1
word2
word3
Extra arguments: (those after --)
extra1
-l
extra2 with spaces
words3

Notice that the order of positional arguments are maintained and no parsing is done on anything after the --, even the unknown option -l

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment