Pure Bash option handling
Posted 04-16-2012 at 01:44 AM by Nominal Animal
I like the standard getopt way of specifying script and/or program parameters, but I don't like its quirks, and it is pretty cryptic if you don't use it often enough.
Here is pure Bash skeleton to implement script option parsing. It is long, but it should be easier to read and understand than one implemented using getopt.
The way this skeleton works is that the huge loop parses all command line parameters, handles both short and long options (-p or -p value or --parameter or --parameter=value or --parameter value), and finally puts back all non-option parameters into the positional parameters list ($1, $2,...).
Option processing stops at -- so that users can supply files beginning with a dash easier.
Parameter - is converted automatically to positional parameter /dev/stdin, i.e. the standard input "file". This way users can specify - to refer to standard input.
Unknown options will abort the script. Currently, the skeleton supports only the standard options -h and --help to output the usage, and an example option -t TYPE or --type=TYPE or --type TYPE .
Run the skeleton to see how it behaves. Any comments or questions are welcome.
Here is pure Bash skeleton to implement script option parsing. It is long, but it should be easier to read and understand than one implemented using getopt.
Code:
#!/bin/bash
set +f # Enable filename globbing
set -B # Enable brace expansion
shopt -s dotglob # Include names that start with a dot
shopt -s nullglob # No match expands to an empty string
# Create a safe temporary directory to put temporary files into,
# and make sure it is automatically deleted after this script exits.
# You can use any filename "$WORK/filename" as a temporary file.
# Omit this if you dont need it.
WORK="$(mktemp -d)" || exit $?
trap "rm -rf '$WORK'" EXIT
# Output usage to standard error, then exit.
# Exit status is optional (default 0), first parameter.
#
Usage () {
exec >&2
echo ""
echo "Usage: $0 [-h|--help]"
echo " $0 [-t TYPE|--type=TYPE] FILES..."
echo ""
exit $[ $1-0 ]
}
# TYPE is stored in this parameter.
# You can also set a default value.
unset Type
# If you want no parameters to yield the usage,
# uncomment the next line:
# [ $# -gt 0 ] || Usage 0
# Parse command line arguments.
#
args=()
while [ $# -gt 0 ]; do
# No options follow --
if [ "$1" = "--" ]; then
shift 1
args=("${args[@]}" "$@")
shift $#
continue
fi
# Not an option?
if [ "${1:0:1}" != "-" ]; then
args[${#args[@]}]="$1"
shift 1
continue
fi
# A long option?
if [ "${1:0:2}" == "--" ]; then
# Skip the two dashes at start, and consume this one
option="${1:2}"
shift 1
# --option=value or --option value
value="${option#*=}"
if [ "$value" = "$option" ]; then
value="$1"
valueshift=1
else
option="${option%%=*}"
valueshift=0
fi
#
# If $value is used, then do
# shift $valueshift
# Long options:
#
case "$option" in
help)
Usage 0
;;
type)
Type="$value"
shift $valueshift
;;
*)
echo "--$option: Unknown option." >&2
exit 1
;;
esac
elif [ "$1" = "-" ]; then
# A single dash is interpreted as "standard input".
shift 1
args[${#args[@]}]="/dev/stdin"
else
# Short option or multiple short options. Consume.
options="${1:1}"
shift 1
# Handle each short option character separately.
while [ ${#options} -gt 0 ]; do
# Short options are handled character-by-character.
option="${options:0:1}"
options="${options:1}"
# Short options:
#
case "$option" in
h)
Usage 0
;;
t)
Type="$1"
shift 1
;;
*)
echo "-$option: Unknown option." >&2
exit 1
;;
esac
done
fi
done
# Set positional arguments "back".
set -- "${args[@]}"
#
# The actual script starts here.
#
if [ $# -gt 0 ]; then
printf '%d command line parameters:\n' $#
printf '\t\047%s\047\n' "$@"
else
printf 'No command line parameters.\n'
fi
if test -v Type ; then
printf 'TYPE was specified as \047%s\047.\n' "$Type"
else
printf 'TYPE was not specified.\n'
fi
Option processing stops at -- so that users can supply files beginning with a dash easier.
Parameter - is converted automatically to positional parameter /dev/stdin, i.e. the standard input "file". This way users can specify - to refer to standard input.
Unknown options will abort the script. Currently, the skeleton supports only the standard options -h and --help to output the usage, and an example option -t TYPE or --type=TYPE or --type TYPE .
Run the skeleton to see how it behaves. Any comments or questions are welcome.
Total Comments 0




