302 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			302 lines
		
	
	
	
		
			8.9 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
#From: "Grigoriy Strokin" <grg@philol.msu.ru>
 | 
						|
#Newsgroups: comp.unix.shell
 | 
						|
#Subject: BASH: getopt function that parses long-named options
 | 
						|
#Date: Mon, 22 Dec 1997 20:35:18 +0300
 | 
						|
 | 
						|
#Hi, I have written a BASH function named getoptex, that is like bash builtin
 | 
						|
#"getopts", but does parse long-named options and optional arguments. It only
 | 
						|
#uses builtin bash commands, so it is very fast.  In order to use it in your
 | 
						|
#bash scripts, include a command ". getopt.sh" (<dot> getopt.sh) to the file
 | 
						|
#containing your script, and that will define functions getopt, getoptex, and
 | 
						|
#optlistex (the file getopt.sh with its detailed description is listed
 | 
						|
#below).
 | 
						|
 | 
						|
#*** file getopt.sh ***
 | 
						|
 | 
						|
#! /bin/bash
 | 
						|
#
 | 
						|
# getopt.sh:
 | 
						|
# functions like getopts but do long-named options parsing
 | 
						|
# and support optional arguments
 | 
						|
#
 | 
						|
# Version 1.0 1997 by Grigoriy Strokin (grg@philol.msu.ru), Public Domain
 | 
						|
# Date created:  December 21, 1997
 | 
						|
# Date modified: December 21, 1997
 | 
						|
#
 | 
						|
# IMPORTANT FEATURES
 | 
						|
#
 | 
						|
# 1) Parses both short and long-named options
 | 
						|
# 2) Supports optional arguments
 | 
						|
# 3) Only uses bash builtins, thus no calls to external
 | 
						|
#    utilities such as expr or sed is done. Therefore,
 | 
						|
#    parsing speed is high enough
 | 
						|
#
 | 
						|
#
 | 
						|
# DESCRIPTION
 | 
						|
#
 | 
						|
# FUNCTION getopt
 | 
						|
# Usage: getopt OPTLIST {"$@"|ALTERNATIVE_PARAMETERS}
 | 
						|
#
 | 
						|
# like getopts, but parse options with both required and optional arguments,
 | 
						|
# Options with optional arguments must have "." instead of ":" after them.
 | 
						|
# Furthemore, a variable name to place option name cannot be specified
 | 
						|
# and is always placed in OPTOPT variable
 | 
						|
#
 | 
						|
# This function is provided for compatibility with getopts()
 | 
						|
# OPTLIST style, and it actually calls getoptex (see bellow)
 | 
						|
#
 | 
						|
# NOTE that a list of parameters is required and must be either "$@",
 | 
						|
# if processing command line arguments, or some alternative parameters.
 | 
						|
#
 | 
						|
# FUNCTION getoptex
 | 
						|
# Usage: getoptex OPTION_LIST {"$@"|ALTERNATIVE_PARAMETERS}
 | 
						|
#
 | 
						|
# like getopts, but parse long-named options.
 | 
						|
#
 | 
						|
# Both getopt and getoptex return 0 if an option has been parsed,
 | 
						|
# and 1 if all options are already parsed or an error occured
 | 
						|
#
 | 
						|
# Both getopt and getoptex set or test the following variables:
 | 
						|
#
 | 
						|
# OPTERR -- tested for whether error messages must be given for invalid
 | 
						|
options
 | 
						|
#
 | 
						|
# OPTOPT -- set to the name of an option parsed,
 | 
						|
#           or to "?" if no more options or error
 | 
						|
# OPTARG -- set to the option argument, if any;
 | 
						|
#           unset if ther is no argument;
 | 
						|
#           on error, set to the erroneous option name
 | 
						|
#
 | 
						|
# OPTIND -- Initialized to 1.
 | 
						|
#           Then set to the number of the next parameter to be parsed
 | 
						|
#           when getopt or getoptex will be called next time.
 | 
						|
#           When all options are parsed, contains a number of
 | 
						|
#           the first non-option argument.
 | 
						|
#
 | 
						|
#
 | 
						|
# OPTOFS -- If a parameter number $OPTIND containg an option parsed
 | 
						|
#           does not contain any more options, OPTOFS is unset;
 | 
						|
#           otherwise, OPTOFS is set to such a number of "?" signs
 | 
						|
#           which is equal to the number of options parsed
 | 
						|
#
 | 
						|
#           You might not set variables OPTIND and OPTOFS yourself
 | 
						|
#           unless you want to parse a list of parameters more than once.
 | 
						|
#           Otherwise, you whould unset OPTIND (or set it to 1)
 | 
						|
#           and unset OPTOFS each time you want to parse a new parameters
 | 
						|
list
 | 
						|
#
 | 
						|
# Option list format is DIFFERENT from one for getopts or getopt.
 | 
						|
getopts-style
 | 
						|
# option list can be converted to getoptex-style using a function optlistex
 | 
						|
# (see bellow)
 | 
						|
#
 | 
						|
# DESCRIPTION of option list used with getoptex:
 | 
						|
# Option names are separated by whitespace. Options consiting of
 | 
						|
# more than one character are treated as long-named (--option)
 | 
						|
#
 | 
						|
# Special characters can appear at the and of option names specifying
 | 
						|
# whether an argument is required (default is ";"):
 | 
						|
# ";" (default) -- no argument
 | 
						|
# ":" -- required argument
 | 
						|
# "," -- optional argument
 | 
						|
#
 | 
						|
# For example, an option list "a b c help version f: file: separator."
 | 
						|
# defines the following options:
 | 
						|
#    -a, -b, -c, --help, --version -- no argument
 | 
						|
#    -f, --file -- argument required
 | 
						|
#    --separator -- optional argument
 | 
						|
#
 | 
						|
# FUNCTION optlistex
 | 
						|
# Usage new_style_optlist=`optlistex OLD_STYLE_OPTLIST`
 | 
						|
#
 | 
						|
# Converts getopts-style option list in a format suitable for use with getoptex
 | 
						|
# Namely, it inserts spaces after each option name.
 | 
						|
#
 | 
						|
#
 | 
						|
# HOW TO USE
 | 
						|
#
 | 
						|
# In order o use in your bash scripts the functions described,
 | 
						|
# include a command ". getopt.sh" to the file containing the script,
 | 
						|
# which will define functions getopt, getoptex, and optlistex
 | 
						|
#
 | 
						|
# EXAMPLES
 | 
						|
#
 | 
						|
# See files 'getopt1' and 'getopt2' that contain sample scripts that use
 | 
						|
# getopt and getoptex functions respectively
 | 
						|
#
 | 
						|
#
 | 
						|
# Please send your comments to grg@philol.msu.ru
 | 
						|
 | 
						|
function getoptex()
 | 
						|
{
 | 
						|
  let $# || return 1
 | 
						|
  local optlist="${1#;}"
 | 
						|
  let OPTIND || OPTIND=1
 | 
						|
  [ $OPTIND -lt $# ] || return 1
 | 
						|
  shift $OPTIND
 | 
						|
  if [ "$1" != "-" -a "$1" != "${1#-}" ]
 | 
						|
  then OPTIND=$[OPTIND+1]; if [ "$1" != "--" ]
 | 
						|
  then
 | 
						|
    local o
 | 
						|
    o="-${1#-$OPTOFS}"
 | 
						|
    for opt in ${optlist#;}
 | 
						|
    do
 | 
						|
      OPTOPT="${opt%[;.:]}"
 | 
						|
      unset OPTARG
 | 
						|
      local opttype="${opt##*[^;:.]}"
 | 
						|
      [ -z "$opttype" ] && opttype=";"
 | 
						|
      if [ ${#OPTOPT} -gt 1 ]
 | 
						|
      then # long-named option
 | 
						|
        case $o in
 | 
						|
          "--$OPTOPT")
 | 
						|
            if [ "$opttype" != ":" ]; then return 0; fi
 | 
						|
            OPTARG="$2"
 | 
						|
            if [ -z "$OPTARG" ];
 | 
						|
            then # error: must have an agrument
 | 
						|
              let OPTERR && echo "$0: error: $OPTOPT must have an argument" >&2
 | 
						|
              OPTARG="$OPTOPT";
 | 
						|
              OPTOPT="?"
 | 
						|
              return 1;
 | 
						|
            fi
 | 
						|
            OPTIND=$[OPTIND+1] # skip option's argument
 | 
						|
            return 0
 | 
						|
          ;;
 | 
						|
          "--$OPTOPT="*)
 | 
						|
            if [ "$opttype" = ";" ];
 | 
						|
            then  # error: must not have arguments
 | 
						|
              let OPTERR && echo "$0: error: $OPTOPT must not have arguments" >&2
 | 
						|
              OPTARG="$OPTOPT"
 | 
						|
              OPTOPT="?"
 | 
						|
              return 1
 | 
						|
            fi
 | 
						|
            OPTARG=${o#"--$OPTOPT="}
 | 
						|
            return 0
 | 
						|
          ;;
 | 
						|
        esac
 | 
						|
      else # short-named option
 | 
						|
        case "$o" in
 | 
						|
          "-$OPTOPT")
 | 
						|
            unset OPTOFS
 | 
						|
            [ "$opttype" != ":" ] && return 0
 | 
						|
            OPTARG="$2"
 | 
						|
            if [ -z "$OPTARG" ]
 | 
						|
            then
 | 
						|
              echo "$0: error: -$OPTOPT must have an argument" >&2
 | 
						|
              OPTARG="$OPTOPT"
 | 
						|
              OPTOPT="?"
 | 
						|
              return 1
 | 
						|
            fi
 | 
						|
            OPTIND=$[OPTIND+1] # skip option's argument
 | 
						|
            return 0
 | 
						|
          ;;
 | 
						|
          "-$OPTOPT"*)
 | 
						|
            if [ $opttype = ";" ]
 | 
						|
            then # an option with no argument is in a chain of options
 | 
						|
              OPTOFS="$OPTOFS?" # move to the next option in the chain
 | 
						|
              OPTIND=$[OPTIND-1] # the chain still has other options
 | 
						|
              return 0
 | 
						|
            else
 | 
						|
              unset OPTOFS
 | 
						|
              OPTARG="${o#-$OPTOPT}"
 | 
						|
              return 0
 | 
						|
            fi
 | 
						|
          ;;
 | 
						|
        esac
 | 
						|
      fi
 | 
						|
    done
 | 
						|
    echo "$0: error: invalid option: $o"
 | 
						|
  fi; fi
 | 
						|
  OPTOPT="?"
 | 
						|
  unset OPTARG
 | 
						|
  return 1
 | 
						|
}
 | 
						|
function optlistex
 | 
						|
{
 | 
						|
  local l="$1"
 | 
						|
  local m # mask
 | 
						|
  local r # to store result
 | 
						|
  while [ ${#m} -lt $[${#l}-1] ]; do m="$m?"; done # create a "???..." mask
 | 
						|
  while [ -n "$l" ]
 | 
						|
  do
 | 
						|
    r="${r:+"$r "}${l%$m}" # append the first character of $l to $r
 | 
						|
    l="${l#?}" # cut the first charecter from $l
 | 
						|
    m="${m#?}"  # cut one "?" sign from m
 | 
						|
    if [ -n "${l%%[^:.;]*}" ]
 | 
						|
    then # a special character (";", ".", or ":") was found
 | 
						|
      r="$r${l%$m}" # append it to $r
 | 
						|
      l="${l#?}" # cut the special character from l
 | 
						|
      m="${m#?}"  # cut one more "?" sign
 | 
						|
    fi
 | 
						|
  done
 | 
						|
  echo $r
 | 
						|
}
 | 
						|
function getopt()
 | 
						|
{
 | 
						|
  local optlist=`optlistex "$1"`
 | 
						|
  shift
 | 
						|
  getoptex "$optlist" "$@"
 | 
						|
  return $?
 | 
						|
}
 | 
						|
 | 
						|
#**************************************
 | 
						|
#     cut here
 | 
						|
#**************************************
 | 
						|
#*** (end of getopt.sh) ***
 | 
						|
 | 
						|
 | 
						|
#*** file getopt1 ***
 | 
						|
 | 
						|
#! /bin/bash
 | 
						|
# getopt1:
 | 
						|
# Sample script using the function getopt
 | 
						|
#
 | 
						|
# Type something like "getopt1 -ab -d 10 -e20 text1 text2"
 | 
						|
# on the command line to see how it works
 | 
						|
#
 | 
						|
# See getopt.sh for more information
 | 
						|
#. getopt.sh
 | 
						|
#echo Using getopt to parse arguments:
 | 
						|
#while getopt "abcd:e." "$@"
 | 
						|
#do
 | 
						|
#  echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}"
 | 
						|
#done
 | 
						|
#shift $[OPTIND-1]
 | 
						|
#for arg in "$@"
 | 
						|
#do
 | 
						|
#  echo "Non option argument <$arg>"
 | 
						|
#done
 | 
						|
#
 | 
						|
#**************************************
 | 
						|
#        cut here
 | 
						|
#**************************************
 | 
						|
#*** (end of getopt1) ***
 | 
						|
#
 | 
						|
#
 | 
						|
#*** file getopt2 ***
 | 
						|
#
 | 
						|
#! /bin/bash
 | 
						|
# getopt2:
 | 
						|
# Sample script using the function getoptex
 | 
						|
#
 | 
						|
# Type something like "getopt2 -ab -d 10 -e20 --opt1 --opt4=100 text1 text2"
 | 
						|
# to see how it works
 | 
						|
#
 | 
						|
# See getopt.sh for more information
 | 
						|
. getopt.sh
 | 
						|
#echo Using getoptex to parse arguments:
 | 
						|
#while getoptex "a; b; c; d: e. opt1 opt2 opt3 opt4: opt5." "$@"
 | 
						|
#do
 | 
						|
#  echo "Option <$OPTOPT> ${OPTARG:+has an arg <$OPTARG>}"
 | 
						|
#done
 | 
						|
#shift $[OPTIND-1]
 | 
						|
#for arg in "$@"
 | 
						|
#do
 | 
						|
#  echo "Non option argument <$arg>"
 | 
						|
#done
 | 
						|
#
 | 
						|
#**************************************
 | 
						|
#         cut here
 | 
						|
#**************************************
 | 
						|
#*** (end of getopt2) ***
 | 
						|
 | 
						|
 |