Everything I see uses getopt
or the slightly-fancier getopts
which only supports one-character options (e.g., -h
but not --help
). I want to do fancy long options.
The shift keyword takes an additional argument of how many positions of the arguments to move the cursor to. To parse the next argument, the shift command has a number 2 assigned to it, which would switch to the next argument. Notice how the script exited when it encountered a double hyphen ( -- ).
Using arguments Inside the script, we can use the $ symbol followed by the integer to access the arguments passed. For example, $1 , $2 , and so on. The $0 will contain the script name.
The special character $# stores the total number of arguments. We also have $@ and $* as wildcard characters which are used to denote all the arguments. We use $$ to find the process ID of the current shell script, while $? can be used to print the exit code for our script.
To parse short command-line options, we can use bash's built-in function getopts. It parses positional parameters as options.
I've done something like this:
_setArgs(){
while [ "${1:-}" != "" ]; do
case "$1" in
"-c" | "--configFile")
shift
configFile=$1
;;
"-f" | "--forceUpdate")
forceUpdate=true
;;
"-r" | "--forceRetry")
forceRetry=true
;;
esac
shift
done
}
As you can see, this supports both the single-character and the longer options nicely. It allows for values to be associated with each argument, as in the case of --configFile
. It's also quite extensible, with no artificial limitations as to what options can be configured, etc.
As included above, the "${1:-}"
prevents an "unbound variable" error when running in bash "strict" mode (set -euo pipefail
).
Assuming that you "want to do fancy long options" regardless of the tool, just go with getopt
(getopts
seems to be mainly used when portability is crucial). Here's an example of about the maximum complexity that you'll get:
params="$(getopt -o e:hv -l exclude:,help,verbose --name "$(basename "$0")" -- "$@")"
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$params"
unset params
while true
do
case $1 in
-e|--exclude)
excludes+=("$2")
shift 2
;;
-h|--help)
usage
;;
-v|--verbose)
verbose='--verbose'
shift
;;
--)
shift
break
;;
*)
usage
;;
esac
done
With this code, you can specify -e
/--exclude
more than once, and ${excludes[@]}
will contain all of the given excludes. After processing (--
is always present) anything remaining is stored in $@
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With