Created
March 20, 2018 18:24
-
-
Save bobpaul/ecd74cdf7681516703f20726431eaceb to your computer and use it in GitHub Desktop.
An example showing how to use getopt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
Background context, references:
https://stackoverflow.com/a/29754866/605356
https://gist.github.com/kaushalmodi/74e9875d5ab0a2bc1010447f1bee5d0a
https://jutahh.link/bash_gnu_getopt_example_script__bobpaul (this web page)
I have forked and updated this gist with shellcheck
and shfmt
. Feel free to merge 🥳
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example usage:
Notice that the order of positional arguments are maintained and no parsing is done on anything after the
--
, even the unknown option-l