Bash Script Argument Parsing

Years ago we came up with a halfway decent way to parse arguments for a shell script. I am posting an example template of how we did that. The goals were to have a readable, self-contained script with most of the flexibility of normal command line argument parsing. This version even handles equal signs for assigning values — something we didn’t bother with before.

#!/bin/bash


prog=$(basename "$0")

# Set defaults.
opt_verbose=0
opt_help=0
opt_number=2

usage="Usage: 
 $prog [<options>] <file1> <file2>
 $prog (-h | --help)
 
Options:
 -n|--number=<num> Number of things (default: $opt_number).
 -v|--verbose Verbose mode.
 -h|--help Show usage.
 <file1> File number 1.
 <file2> File number 2.
 
This is a template for a bash script that
handles command line options."

while true ; do
 test $# -gt 0 || break
 value=$(echo "$1" | sed -e 's/.*=//')
 test "$value" = "$1" && value=""
 case $1 in
 -v|--verbose)
 shift 1
 opt_verbose=1
 ;;
 -h|--help)
 echo "$usage" >&2
 exit 1
 ;;
 -n|--number*)
 shift 1
 test "$value" = "" && value="$1" && shift 1
 opt_number="$value"
 ;;
 *)
 break
 ;;
 esac
done

if test $# -lt 2 ; then
 echo "Error: Not enough arguments"
 echo "$usage" >&2
 exit 1
fi

file1="$1"
shift 1
file2="$1"
shift 1

if test $# -gt 0 ; then
 echo "Error: Too many arguments: $*"
 echo "$usage" >&2
 exit 1
fi

echo "opt_number: $opt_number"
echo "opt_verbose: $opt_verbose"
echo "opt_help: $opt_help"
echo "file1: $file1"
echo "file2: $file2"