1#From: "Grigoriy Strokin" <grg@philol.msu.ru> 2#Newsgroups: comp.unix.shell 3#Subject: BASH: getopt function that parses long-named options 4#Date: Mon, 22 Dec 1997 20:35:18 +0300 5 6#Hi, I have written a BASH function named getoptex, that is like bash builtin 7#"getopts", but does parse long-named options and optional arguments. It only 8#uses builtin bash commands, so it is very fast. In order to use it in your 9#bash scripts, include a command ". getopt.sh" (<dot> getopt.sh) to the file 10#containing your script, and that will define functions getopt, getoptex, and 11#optlistex (the file getopt.sh with its detailed description is listed 12#below). 13 14#*** file getopt.sh *** 15 16#! /bin/bash 17# 18# getopt.sh: 19# functions like getopts but do long-named options parsing 20# and support optional arguments 21# 22# Version 1.0 1997 by Grigoriy Strokin (grg@philol.msu.ru), Public Domain 23# Date created: December 21, 1997 24# Date modified: December 21, 1997 25# 26# IMPORTANT FEATURES 27# 28# 1) Parses both short and long-named options 29# 2) Supports optional arguments 30# 3) Only uses bash builtins, thus no calls to external 31# utilities such as expr or sed is done. Therefore, 32# parsing speed is high enough 33# 34# 35# DESCRIPTION 36# 37# FUNCTION getopt 38# Usage: getopt OPTLIST {"$@"|ALTERNATIVE_PARAMETERS} 39# 40# like getopts, but parse options with both required and optional arguments, 41# Options with optional arguments must have "." instead of ":" after them. 42# Furthemore, a variable name to place option name cannot be specified 43# and is always placed in OPTOPT variable 44# 45# This function is provided for compatibility with getopts() 46# OPTLIST style, and it actually calls getoptex (see bellow) 47# 48# NOTE that a list of parameters is required and must be either "$@", 49# if processing command line arguments, or some alternative parameters. 50# 51# FUNCTION getoptex 52# Usage: getoptex OPTION_LIST {"$@"|ALTERNATIVE_PARAMETERS} 53# 54# like getopts, but parse long-named options. 55# 56# Both getopt and getoptex return 0 if an option has been parsed, 57# and 1 if all options are already parsed or an error occured 58# 59# Both getopt and getoptex set or test the following variables: 60# 61# OPTERR -- tested for whether error messages must be given for invalid 62options 63# 64# OPTOPT -- set to the name of an option parsed, 65# or to "?" if no more options or error 66# OPTARG -- set to the option argument, if any; 67# unset if ther is no argument; 68# on error, set to the erroneous option name 69# 70# OPTIND -- Initialized to 1. 71# Then set to the number of the next parameter to be parsed 72# when getopt or getoptex will be called next time. 73# When all options are parsed, contains a number of 74# the first non-option argument. 75# 76# 77# OPTOFS -- If a parameter number $OPTIND containg an option parsed 78# does not contain any more options, OPTOFS is unset; 79# otherwise, OPTOFS is set to such a number of "?" signs 80# which is equal to the number of options parsed 81# 82# You might not set variables OPTIND and OPTOFS yourself 83# unless you want to parse a list of parameters more than once. 84# Otherwise, you whould unset OPTIND (or set it to 1) 85# and unset OPTOFS each time you want to parse a new parameters 86list 87# 88# Option list format is DIFFERENT from one for getopts or getopt. 89getopts-style 90# option list can be converted to getoptex-style using a function optlistex 91# (see bellow) 92# 93# DESCRIPTION of option list used with getoptex: 94# Option names are separated by whitespace. Options consiting of 95# more than one character are treated as long-named (--option) 96# 97# Special characters can appear at the and of option names specifying 98# whether an argument is required (default is ";"): 99# ";" (default) -- no argument 100# ":" -- required argument 101# "," -- optional argument 102# 103# For example, an option list "a b c help version f: file: separator." 104# defines the following options: 105# -a, -b, -c, --help, --version -- no argument 106# -f, --file -- argument required 107# --separator -- optional argument 108# 109# FUNCTION optlistex 110# Usage new_style_optlist=`optlistex OLD_STYLE_OPTLIST` 111# 112# Converts getopts-style option list in a format suitable for use with getoptex 113# Namely, it inserts spaces after each option name. 114# 115# 116# HOW TO USE 117# 118# In order o use in your bash scripts the functions described, 119# include a command ". getopt.sh" to the file containing the script, 120# which will define functions getopt, getoptex, and optlistex 121# 122# EXAMPLES 123# 124# See files 'getopt1' and 'getopt2' that contain sample scripts that use 125# getopt and getoptex functions respectively 126# 127# 128# Please send your comments to grg@philol.msu.ru 129 130function getoptex() 131{ 132 let $# || return 1 133 local optlist="${1#;}" 134 let OPTIND || OPTIND=1 135 [ $OPTIND -lt $# ] || return 1 136 shift $OPTIND 137 if [ "$1" != "-" ] && [ "$1" != "${1#-}" ] 138 then OPTIND=$[OPTIND+1]; if [ "$1" != "--" ] 139 then 140 local o 141 o="-${1#-$OPTOFS}" 142 for opt in ${optlist#;} 143 do 144 OPTOPT="${opt%[;.:]}" 145 unset OPTARG 146 local opttype="${opt##*[^;:.]}" 147 [ -z "$opttype" ] && opttype=";" 148 if [ ${#OPTOPT} -gt 1 ] 149 then # long-named option 150 case $o in 151 "--$OPTOPT") 152 if [ "$opttype" != ":" ]; then return 0; fi 153 OPTARG="$2" 154 if [ -z "$OPTARG" ]; 155 then # error: must have an agrument 156 let OPTERR && echo "$0: error: $OPTOPT must have an argument" >&2 157 OPTARG="$OPTOPT"; 158 OPTOPT="?" 159 return 1; 160 fi 161 OPTIND=$[OPTIND+1] # skip option's argument 162 return 0 163 ;; 164 "--$OPTOPT="*) 165 if [ "$opttype" = ";" ]; 166 then # error: must not have arguments 167 let OPTERR && echo "$0: error: $OPTOPT must not have arguments" >&2 168 OPTARG="$OPTOPT" 169 OPTOPT="?" 170 return 1 171 fi 172 OPTARG=${o#"--$OPTOPT="} 173 return 0 174 ;; 175 esac 176 else # short-named option 177 case "$o" in 178 "-$OPTOPT") 179 unset OPTOFS 180 [ "$opttype" != ":" ] && return 0 181 OPTARG="$2" 182 if [ -z "$OPTARG" ] 183 then 184 echo "$0: error: -$OPTOPT must have an argument" >&2 185 OPTARG="$OPTOPT" 186 OPTOPT="?" 187 return 1 188 fi 189 OPTIND=$[OPTIND+1] # skip option's argument 190 return 0 191 ;; 192 "-$OPTOPT"*) 193 if [ $opttype = ";" ] 194 then # an option with no argument is in a chain of options 195 OPTOFS="$OPTOFS?" # move to the next option in the chain 196 OPTIND=$[OPTIND-1] # the chain still has other options 197 return 0 198 else 199 unset OPTOFS 200 OPTARG="${o#-$OPTOPT}" 201 return 0 202 fi 203 ;; 204 esac 205 fi 206 done 207 echo "$0: error: invalid option: $o" 208 fi; fi 209 OPTOPT="?" 210 unset OPTARG 211 return 1 212} 213function optlistex 214{ 215 local l="$1" 216 local m # mask 217 local r # to store result 218 while [ ${#m} -lt $[${#l}-1] ]; do m="$m?"; done # create a "???..." mask 219 while [ -n "$l" ] 220 do 221 r="${r:+"$r "}${l%$m}" # append the first character of $l to $r 222 l="${l#?}" # cut the first charecter from $l 223 m="${m#?}" # cut one "?" sign from m 224 if [ -n "${l%%[^:.;]*}" ] 225 then # a special character (";", ".", or ":") was found 226 r="$r${l%$m}" # append it to $r 227 l="${l#?}" # cut the special character from l 228 m="${m#?}" # cut one more "?" sign 229 fi 230 done 231 echo $r 232} 233function getopt() 234{ 235 local optlist=`optlistex "$1"` 236 shift 237 getoptex "$optlist" "$@" 238 return $? 239} 240 241#************************************** 242# cut here 243#************************************** 244#*** (end of getopt.sh) *** 245 246 247#*** file getopt1 *** 248 249#! /bin/bash 250# getopt1: 251# Sample script using the function getopt 252# 253# Type something like "getopt1 -ab -d 10 -e20 text1 text2" 254# on the command line to see how it works 255# 256# See getopt.sh for more information 257#. getopt.sh 258#echo Using getopt to parse arguments: 259#while getopt "abcd:e." "$@" 260#do 261# echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}" 262#done 263#shift $[OPTIND-1] 264#for arg in "$@" 265#do 266# echo "Non option argument <$arg>" 267#done 268# 269#************************************** 270# cut here 271#************************************** 272#*** (end of getopt1) *** 273# 274# 275#*** file getopt2 *** 276# 277#! /bin/bash 278# getopt2: 279# Sample script using the function getoptex 280# 281# Type something like "getopt2 -ab -d 10 -e20 --opt1 --opt4=100 text1 text2" 282# to see how it works 283# 284# See getopt.sh for more information 285. getopt.sh 286#echo Using getoptex to parse arguments: 287#while getoptex "a; b; c; d: e. opt1 opt2 opt3 opt4: opt5." "$@" 288#do 289# echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}" 290#done 291#shift $[OPTIND-1] 292#for arg in "$@" 293#do 294# echo "Non option argument <$arg>" 295#done 296# 297#************************************** 298# cut here 299#************************************** 300#*** (end of getopt2) *** 301 302