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