Source code in Skeleton.sh

To see how this is used return to this tutorial index.

#!/bin/ksh -u
# This is a skeleton shell script with long argument processing.
# Copyright (c) Alain D D Williams <addw@phcomp.co.uk> January 2012-2020
# It is expected that you will modify this skeleton for your own use.
# This code is released as free software under the BSD 3 clause license:
#   https://directory.fsf.org/wiki/License:BSD-3-Clause

# Try this out by running:
#	ksh -u Skeleton.sh --na=SomeArgument --oa --oa=OptionalArgument a b c
# This also works with modern versions of bash

# SCCS: @(#)Skeleton.sh	1.7 10/26/20 13:44:59

PROGNAME=${0##*/}


function Die {
	echo "$PROGNAME: $*" >&2
	exit 2
}

# Generate a note in verbose mode
# If the first arg is a digit, only log if $verbose is at least that number.
function Note {
	typeset -i level=1
	(( $# > 1 )) && [[ $1 == [0-9] ]] && level=$1 && shift
	(( verbose < level )) && return
	echo "$*" >&2
}

# Log to user & file, unless quiet.
# If option '-b' put a blank line out first.
function Log {
	(( quiet == 1 )) && return

	echo "$PROGNAME: $*" >&2
}

# Generate a usage message and exit. If there is an argument print it and exit code is 2
function Usage {
	(( $# > 0 )) && echo "$PROGNAME: $*" >&2 && ec=2 || ec=0

	sed -e 's/^^//' <<-!
	Description ... blah, blah
	Usage: $PROGNAME [-opts] [files]
	-h --help
	^	Help message
	--na=arg
	^	A long option that needs an argument
	^	Can use space instead of '=': --na arg
	--oa[=arg]
	^	A long option that has an optional argument
	^	Here the '=' cannot be replaced by a space
	-q --quiet
	^	Don't complain about non errors
	-v	Verbose - say a bit more than usual about what is happening.
	^	Give this more than once for increased verbosity.
	- --	Denotes the end of the options.  Arguments after this will be handled as file names
	^	even if they start with a '-'.
	^	This may either be a '-' or '--'.
	More words
	Version: 1.7 10/26/20
	!
	exit $ec
}


# **** Start ****
verbose=0
quiet=0

# Long Options, value: 0 - no argument, 1 - required argument, 2 - optional argument
typeset -A LongOpts=([help]=0 [quiet]=0 [na]=1 [oa]=2)
ShortOpts=:hqv

# Parse options, recognise --options
while	(( $# >= $OPTIND )) && eval opt=\${$OPTIND} || break
	[[ $opt == - ]] && shift && break
	if [[ $opt == --?* ]]
	then	opt=${opt#--}
		shift

		# Argument to option ?
		[[ $opt == *=* ]] && OPTARG=${opt#*=} && opt=${opt%=$OPTARG} && hasArg=1 || typeset OPTARG= hasArg=0

		# Check if known option and if it has an argument if it must have one:
		if [[ -z ${LongOpts[$opt]:-} ]]
		then	OPTARG=$opt && opt='?'
		else	if [[ $hasArg = 0 && ${LongOpts[$opt]} = 1 ]]
			then	# Required argument. Can grab next arg ?
				if (( $# >= $OPTIND ))
				then	OPTARG=$1   && shift
				else	OPTARG=$opt && opt=:
				fi
			fi
			[[ $hasArg = 1 && ${LongOpts[$opt]} = 0 ]] && OPTARG=$opt && opt=::
		fi
		true # for the while

	else	getopts $ShortOpts opt
	fi
do	case "$opt" in
	h|help)	Usage ;;
	q|quiet)quiet=1 ;;
	na)	echo "Option --na has the argument that it needs: '$OPTARG'" ;;
	oa)	if [[ $hasArg = 1 ]]
		then	echo "Option --oa has optional argument: '$OPTARG'"
		else	echo "Option --oa does not have an optional argument"
		fi ;;
	v)	(( verbose++ )) ;;
	::)	Usage "Unexpected argument to option '$OPTARG'" ;;
	:)	Usage "Missing argument to option '$OPTARG'" ;;
	\?)	Usage "Unknown option '$OPTARG'" ;;
	*)	Usage "Internal program error, unrecognised argument '$opt'" ;;
	esac
done
shift $(( OPTIND - 1 ))

echo "verbose=$verbose quiet=$quiet"

for a
do	echo "arg='$a'"
done

# end

Return to this tutorial index.