This article needs additional citations for
verification. (February 2017) |
Developer(s) | Various open-source and commercial developers |
---|---|
Initial release | 1986 |
Operating system | Unix, Unix-like, IBM i |
Type | Command |
getopts
is a
built-in
Unix shell command for parsing
command-line arguments. It is designed to process command line arguments that follow the POSIX Utility Syntax Guidelines, based on the C interface of
getopt.
The predecessor to getopts
was the external program getopt
by
Unix System Laboratories.
The original getopt
had several problems: it could not handle whitespace or shell metacharacters in arguments, and there was no ability to disable the output of error messages.
[1]
getopts
was first introduced in 1986 in the
Bourne shell shipped with Unix SVR3. It uses the shell's own variables to track the position of current and argument positions, OPTIND and OPTARG, and returns the option name in a shell variable.
[2] Earlier versions of the Bourne shell did not have getopts.
In 1995, getopts
was included in the
Single UNIX Specification version 1 /
X/Open Portability Guidelines Issue 4.
[3] As a result, getopts
is now available in shells including the
Bourne shell,
KornShell,
Almquist shell,
Bash and
Zsh.
[4]
The getopts command has also been ported to the IBM i operating system. [5]
The modern usage of getopt
was partially revived mainly due to an enhanced implementation in
util-linux. This version, based on the BSD getopt
, not only fixed the two complaints around the old getopt
, but also introduced the capability for parsing GNU-style long options and optional arguments for options, features that getopts
lacks.
[6] The various BSD distributions, however, stuck to the old implementation.
[1]
The usage synopsis of getopt and getopts is similar to its C sibling:
getopt optstring [parameters] getopts optstring varname [parameters]
The way one uses the commands however varies a lot:
In spring 2004 (Solaris 10 beta development), the libc implementation for getopt() was enhanced to support long options. As a result, this new feature was also available in the built-in command getopts
of the Bourne Shell. This is triggered by parenthesized suffixes in the optstring specifying long aliases.
[7]
KornShell and
Zsh both have an extension for long arguments. The former is defined as in Solaris,
[8] while the latter is implemented via a separate zparseopts
command.
[9]
KornShell additionally implements optstring extensions for options beginning with +
instead of -
.
[8]
An alternative to getopts
is the Linux enhanced version of getopt
, the external command line program.
The Linux enhanced version of getopt
has the extra safety of getopts
plus more advanced features. It supports long option names (e.g. --help
) and the options do not have to appear before all the operands (e.g. command operand1 operand2 -a operand3 -b
is permitted by the Linux enhanced version of getopt
but does not work with getopts
). It also supports escaping metacharacters for shells (like
tcsh and
POSIX sh) and optional arguments.
[6]
Program Feature |
POSIX getopts | Solaris/ksh getopts | Unix/BSD getopt | Linux getopt |
---|---|---|---|---|
Splits options for easy parsing | Yes | Yes | Yes | Yes |
Allows suppressing error messages | Yes | Yes | No | Yes |
Safe with whitespace and metacharacters | Yes | Yes | No | Yes |
Allows operands to be mixed with options | No | Yes | No | Yes |
Supports long options | Emulation | Yes | No | Yes |
Optional arguments | Error handling | Error handling | No | Yes |
Suppose we are building a Wikipedia downloader in bash that takes three options and zero extra arguments:
wpdown -a article name -l [language] -v
When possible, we allow the following long arguments:
-a --article -l --language, --lang -v --verbose
For clarity, no help text is included, and we assume there is a program that downloads any webpage. In addition, all programs are of the form:
#!/bin/bash
VERBOSE=0
ARTICLE=''
LANG=en
# [EXAMPLE HERE]
if ((VERBOSE > 2)); then
printf '%s\n' 'Non-option arguments:'
printf '%q ' "${remaining[@]]}"
fi
if ((VERBOSE > 1)); then
printf 'Downloading %s:%s\n' "$LANG" "$ARTICLE"
fi
if [[ ! $ARTICLE ]]; then
printf '%s\n' "No articles!">&2
exit 1
fi
save_webpage "https://${LANG}.wikipedia.org/wiki/${ARTICLE}"
The old getopt does not support optional arguments:
# parse everything; if it fails we bail
args=`getopt 'a:l:v' $*` || exit
# now we have the sanitized args... replace the original with it
set -- $args
while true; do
case $1 in
(-v) ((VERBOSE++)); shift;;
(-a) ARTICLE=$2; shift 2;;
(-l) LANG=$2; shift 2;;
(--) shift; break;;
(*) exit 1;; # error
esac
done
remaining=("$@")
This script will also break with any article title with a space or a shell metacharacter (like ? or *) in it.
Getopts give the script the look and feel of the C interface, although in POSIX optional arguments are still absent:
#!/bin/sh
while getopts ':a:l:v' opt; do
case $opt in
(v) ((VERBOSE++));;
(a) ARTICLE=$OPTARG;;
(l) LANG=$OPTARG;;
(:) # "optional arguments" (missing option-argument handling)
case $OPTARG in
(a) exit 1;; # error, according to our syntax
(l) :;; # acceptable but does nothing
esac;;
esac
done
shift $((OPTIND-1))
# remaining is "$@"
Since we are no longer operating on shell options directly, we no longer need to shift them within the loop. However, a slicing operation is required to remove the parsed options and leave the remaining arguments.
It is fairly simple to emulate long option support of flags by treating --fast
as an argument fast
to an option -
. That is, -:
is added to the optstring, and -
is added as a case for opt
, within which OPTARG
is evaluated for a match to fast
. Supporting long options with an argument is more tedious, but is possible when the options and arguments are delineated by =.
[10]
Linux getopt escapes its output and an "eval" command is needed to have the shell interpret it. The rest is unchanged:
#!/bin/bash
# We use "${@}" instead of "${*}" to preserve argument-boundary information
ARGS=$(getopt --options 'a:l::v' --longoptions 'article:,lang::,language::,verbose' -- "${@}") || exit
eval "set -- ${ARGS}"
while true; do
case "${1}" in
(-v | --verbose)
((VERBOSE++))
shift
;;
(-a | --article)
ARTICLE="${2}"
shift 2
;;
(-l | --lang | --language)
# handle optional: getopt normalizes it into an empty string
if -n "${2}" ; then
LANG="${2}"
fi
shift 2
;;
(--)
shift
break
;;
(*)
exit 1 # error
;;
esac
done
remaining_args=("${@}")
This article needs additional citations for
verification. (February 2017) |
Developer(s) | Various open-source and commercial developers |
---|---|
Initial release | 1986 |
Operating system | Unix, Unix-like, IBM i |
Type | Command |
getopts
is a
built-in
Unix shell command for parsing
command-line arguments. It is designed to process command line arguments that follow the POSIX Utility Syntax Guidelines, based on the C interface of
getopt.
The predecessor to getopts
was the external program getopt
by
Unix System Laboratories.
The original getopt
had several problems: it could not handle whitespace or shell metacharacters in arguments, and there was no ability to disable the output of error messages.
[1]
getopts
was first introduced in 1986 in the
Bourne shell shipped with Unix SVR3. It uses the shell's own variables to track the position of current and argument positions, OPTIND and OPTARG, and returns the option name in a shell variable.
[2] Earlier versions of the Bourne shell did not have getopts.
In 1995, getopts
was included in the
Single UNIX Specification version 1 /
X/Open Portability Guidelines Issue 4.
[3] As a result, getopts
is now available in shells including the
Bourne shell,
KornShell,
Almquist shell,
Bash and
Zsh.
[4]
The getopts command has also been ported to the IBM i operating system. [5]
The modern usage of getopt
was partially revived mainly due to an enhanced implementation in
util-linux. This version, based on the BSD getopt
, not only fixed the two complaints around the old getopt
, but also introduced the capability for parsing GNU-style long options and optional arguments for options, features that getopts
lacks.
[6] The various BSD distributions, however, stuck to the old implementation.
[1]
The usage synopsis of getopt and getopts is similar to its C sibling:
getopt optstring [parameters] getopts optstring varname [parameters]
The way one uses the commands however varies a lot:
In spring 2004 (Solaris 10 beta development), the libc implementation for getopt() was enhanced to support long options. As a result, this new feature was also available in the built-in command getopts
of the Bourne Shell. This is triggered by parenthesized suffixes in the optstring specifying long aliases.
[7]
KornShell and
Zsh both have an extension for long arguments. The former is defined as in Solaris,
[8] while the latter is implemented via a separate zparseopts
command.
[9]
KornShell additionally implements optstring extensions for options beginning with +
instead of -
.
[8]
An alternative to getopts
is the Linux enhanced version of getopt
, the external command line program.
The Linux enhanced version of getopt
has the extra safety of getopts
plus more advanced features. It supports long option names (e.g. --help
) and the options do not have to appear before all the operands (e.g. command operand1 operand2 -a operand3 -b
is permitted by the Linux enhanced version of getopt
but does not work with getopts
). It also supports escaping metacharacters for shells (like
tcsh and
POSIX sh) and optional arguments.
[6]
Program Feature |
POSIX getopts | Solaris/ksh getopts | Unix/BSD getopt | Linux getopt |
---|---|---|---|---|
Splits options for easy parsing | Yes | Yes | Yes | Yes |
Allows suppressing error messages | Yes | Yes | No | Yes |
Safe with whitespace and metacharacters | Yes | Yes | No | Yes |
Allows operands to be mixed with options | No | Yes | No | Yes |
Supports long options | Emulation | Yes | No | Yes |
Optional arguments | Error handling | Error handling | No | Yes |
Suppose we are building a Wikipedia downloader in bash that takes three options and zero extra arguments:
wpdown -a article name -l [language] -v
When possible, we allow the following long arguments:
-a --article -l --language, --lang -v --verbose
For clarity, no help text is included, and we assume there is a program that downloads any webpage. In addition, all programs are of the form:
#!/bin/bash
VERBOSE=0
ARTICLE=''
LANG=en
# [EXAMPLE HERE]
if ((VERBOSE > 2)); then
printf '%s\n' 'Non-option arguments:'
printf '%q ' "${remaining[@]]}"
fi
if ((VERBOSE > 1)); then
printf 'Downloading %s:%s\n' "$LANG" "$ARTICLE"
fi
if [[ ! $ARTICLE ]]; then
printf '%s\n' "No articles!">&2
exit 1
fi
save_webpage "https://${LANG}.wikipedia.org/wiki/${ARTICLE}"
The old getopt does not support optional arguments:
# parse everything; if it fails we bail
args=`getopt 'a:l:v' $*` || exit
# now we have the sanitized args... replace the original with it
set -- $args
while true; do
case $1 in
(-v) ((VERBOSE++)); shift;;
(-a) ARTICLE=$2; shift 2;;
(-l) LANG=$2; shift 2;;
(--) shift; break;;
(*) exit 1;; # error
esac
done
remaining=("$@")
This script will also break with any article title with a space or a shell metacharacter (like ? or *) in it.
Getopts give the script the look and feel of the C interface, although in POSIX optional arguments are still absent:
#!/bin/sh
while getopts ':a:l:v' opt; do
case $opt in
(v) ((VERBOSE++));;
(a) ARTICLE=$OPTARG;;
(l) LANG=$OPTARG;;
(:) # "optional arguments" (missing option-argument handling)
case $OPTARG in
(a) exit 1;; # error, according to our syntax
(l) :;; # acceptable but does nothing
esac;;
esac
done
shift $((OPTIND-1))
# remaining is "$@"
Since we are no longer operating on shell options directly, we no longer need to shift them within the loop. However, a slicing operation is required to remove the parsed options and leave the remaining arguments.
It is fairly simple to emulate long option support of flags by treating --fast
as an argument fast
to an option -
. That is, -:
is added to the optstring, and -
is added as a case for opt
, within which OPTARG
is evaluated for a match to fast
. Supporting long options with an argument is more tedious, but is possible when the options and arguments are delineated by =.
[10]
Linux getopt escapes its output and an "eval" command is needed to have the shell interpret it. The rest is unchanged:
#!/bin/bash
# We use "${@}" instead of "${*}" to preserve argument-boundary information
ARGS=$(getopt --options 'a:l::v' --longoptions 'article:,lang::,language::,verbose' -- "${@}") || exit
eval "set -- ${ARGS}"
while true; do
case "${1}" in
(-v | --verbose)
((VERBOSE++))
shift
;;
(-a | --article)
ARTICLE="${2}"
shift 2
;;
(-l | --lang | --language)
# handle optional: getopt normalizes it into an empty string
if -n "${2}" ; then
LANG="${2}"
fi
shift 2
;;
(--)
shift
break
;;
(*)
exit 1 # error
;;
esac
done
remaining_args=("${@}")