Skip to content

getopt & getopts tutorial

We often encounter scenarios in which command line parameters need to be obtained in Shell scripts. The easiest way is to obtain them through $1, $2……. This method is simple and practical for scenarios that only require one or two parameters, but it will cause some problems for more complex scenarios that require multiple parameters and optional parameters:

  • The order of parameter input must be strictly followed, which is not easy to remember and error-prone
  • Unable to provide “parameter default value”
  • The meaning of the parameters is not clear enough

As an example, suppose we have a script to connect to the host, and the following parameters need to be passed in:

  • username
  • password
  • Host (required, not optional, no need to specify the parameter name)
  • port
  • Show connection details

If the parameters are obtained through $1 and $2, the problems raised above will become more obvious.

We prefer to pass parameters in a way similar to the following:

$ myscript -u username -p password -v -n 9999 192.168.1.2

This is where getopt / getopts comes into play.

getopts vs getopt

Both getopt and getopts are tools used in Bash to obtain and analyze command line parameters, and are often used in shell scripts to analyze script parameters.

  • getopts is a shell builtin and getopt is a standalone external tool
  • getopts uses a simple syntax, and getopt uses a more complex syntax
  • getopts does not support long parameters (eg: --option), getopt supports long parameters
  • The purpose of getopts is to replace getopt in less complex scenarios to perform parameter analysis more quickly
  • getopts is responsible for parameter parsing, which can easily extract parameter values, getopt is only responsible for rearranging parameters according to the rules, further analysis needs to be written by yourself

getopts usage instructions

1. Example

According to the aforementioned case:

$ myscript.sh -u username -p password -v -n 8888 127.0.0.1

Parameter Description:

parameterdescription
-uusername
-ppassword
-nport
-vshow details
no name parameterhost
#!/bin/bash

# Handle script parameters
# -u username
# -p password
# -v Whether to display details
# -n port
while getopts ":u:p:n:v" opt_name # Through the loop, use getopts to parse according to the specified parameter list, and store the parameter name in opt_name
do
  case "$opt_name" in # Judging the processing branch according to the parameter name
       'u') # -u
           CONN_USERNAME="$OPTARG" # get parameter value from $OPTARG
          ;;
       'p') # -p
           CONN_PASSWORD="$OPTARG"
          ;;
       'v') # -v
           CONN_SHOW_DETAIL=true
          ;;
       'n') # -n
           CONN_PORT="$OPTARG"
          ;;
      ?) # other unspecified name parameters
           echo "Unknown argument(s)."
           exit 2
          ;;
   esac
done

# remove parsed parameters
shift $((OPTIND-1))

# Get the host through the first unnamed parameter
CONN_HOST="$1"

# Display the result of getting parameters
echo username "$CONN_USERNAME"
echo password "$CONN_PASSWORD"
echo host "$CONN_HOST"
echo port "$CONN_PORT"
echo show details "$CONN_SHOW_DETAIL"

2. Description

The way getopts works is:

(1) Specify the parameter name that needs to be parsed in the command line

In this example, :u:p:n:v is to specify the name of the parameter to be parsed.

Rule description:

  • The letters in it represent the parameter names that need to be parsed
  • The colon : after the letter means that in addition to itself, the parameter will also take a parameter as the value of the option, and the value passed in is obtained through the $OPTARG variable
  • There is no colon : after the letter, indicating that the parameter is a switch type option, no need to specify a value, it is only used as a mark of existence
  • The colon : at the beginning of the string indicates that during the parsing process, an error message will not be displayed if a parameter that is not specified in the getopts parameter list is encountered. Otherwise an error will be reported.

(2) Read the parameters one by one through the loop

When using getopts to parse parameters, it will be parsed in order according to the specified parameter list. If this parsing conforms to the specified parameter rules, including the parameter name, whether a value needs to be passed, etc., it will return success, and continue parsing in the next cycle, otherwise exit the cycle.

Failure rules:

  • encountered an undefined variable
  • Encountered an unexpected value, such as: specifying a parameter after a parameter that does not need to pass a value, or passing in more values than expected

Exit the loop on failure.

Notice! ! ! Parameters without names must be written at the end! Otherwise, it will be regarded as an unexpected parameter, causing the parsing to stop.

(3) After parsing all expected parameters, process the remaining parameters

After parsing all expected parameters (the loop will exit at this time), the variable $OPTIND stores the Index of the last parsed parameter. If there are other parameters, it is considered to be an unexpected parameter of getopts. At this time, you can cooperate with shift to clear the parsed parameters, and get the remaining parameters through $1 and $2.

shift $((OPTIND-1))

3. Limitations of getopts

For commonly used and less complicated scenarios, using getopts to process parameters is basically sufficient and more convenient, and it is an internal command, which does not need to consider installation issues, but there are also some limitations:

  • The format of the option parameter must be -d val instead of -dval without spaces
  • All option parameters must be written in front of other parameters, because getopts starts processing from the front of the command line, and it will stop when it encounters a parameter that does not start with -, or the option parameter end tag --, if If you encounter non-option command line parameters in the middle, you will not be able to get the following option parameters.
  • long options like --debug are not supported
/usr/share/doc/util-linux-2.23.2
/usr/share/getopt/
/usr/share/docs/

This example refers to the following script:

/usr/share/doc/util-linux-2.23.2/getopt-parse.bash

The built-in getopt function of macOS is relatively weak and does not support long options. You can install the GNU version gnu-getopt:

$ brew install gnu-getopt

2. Introduction

The help information is as follows:

$ getopt --help

usage:
getopt optstring parameters
getopt [options] [--] optstring parameters
getopt [options] -o|--options optstring [options] [--] parameters

options:
-a, --alternative allow long options to start with -
-h, --help this short usage guide
-l, --longoptions <long options> long options to recognize
-n, --name <program name> program name to report errors to
-o, --options <options string> Short options to recognize
-q, --quiet suppress error reporting by getopt(3)
-Q, --quiet-output no quiet output
-s, --shell <shell> set shell quoting rules
-T, --test test getopt(1) version
-u, --unquoted unquote output
-V, --version output version information

3. Examples

According to the case mentioned above, here is a “log level” option, which has a default value, and you can also specify the parameter value yourself.

# short parameter format
$ myscript -u username -p password -v -n 9999 192.168.1.2 -l3
# or long parameter format
$ myscript --username username --password password --verbose --port 9999 192.168.1.2 --log-level=3

Parameter Description:

parameterdescription
-u, --usernameusername
-p, --passwordpassword
-n, --portport
-v, --verboseshow details
-l, --log-levellog level, the default level is 1
no name parameterhost
#!/bin/bash

# Use `"$@"' to have each command-line argument expand to a separate word. The quotes around `$@' are essential!
# Use getopt to tidy up parameters
ARGS=$(getopt -o 'u:p:n:vl::' -l 'username:,password:,port:,verbose,log-level::' -- "$@")

if [ $? != 0 ] ; then echo "Parse error! Terminating..." >&2 ; exit 1 ;

# Set the parameters to getopt's sorted parameters
# $ARGS needs to be surrounded by quotes
eval set -- "$ARGS"

# loop parsing parameters
while true ;
    # start parsing from the first parameter
    case "$1" in
         # Username needs to have parameter value, so get the parameter value through $2, after getting it, use shift to clear the obtained parameters
         -u|--username) CONN_USERNAME="$2" ; shift 2 ;;
         # password, the acquisition rules are the same as above
         -p|--password) CONN_PASSWORD="$2" ; shift 2 ;;
         # Port, get the same rules as above
         -n|--port) CONN_PORT="$2" ; shift 2 ;;
         # Whether to display details, switch parameters, with this option, this branch will be executed
         -v|--verbose) CONN_SHOW_DETAIL=true ; shift ;;
         # log level, default parameter
         # Short form: -l3
         # Long format: --log-level=3
         -l|--log-level)
              # If the parameter item is specified, but the parameter value is not specified, an empty string will be obtained by default, and the default value can be used according to this rule
              # If a parameter value is specified, use the parameter value
              case "$2" in
                   "") CONN_LOG_LEVEL=1 ; shift 2 ;;
                  *) CONN_LOG_LEVEL="$2" ; shift 2 ;;
              esac;;
         --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done

# Get the host through the first unnamed parameter
CONN_HOST="$1"

# Display the result of getting parameters
echo 'Username: ' "$CONN_USERNAME"
echo 'Password:' "$CONN_PASSWORD"
echo 'Host: ' "$CONN_HOST"
echo 'Port: ' "$CONN_PORT"
echo 'Display details: ' "$CONN_SHOW_DETAIL"
echo 'Log level: ' "$CONN_LOG_LEVEL"

4. Description

In fact, getopt is only responsible for rearranging parameters, and does not care about extracting parameter values. It will focus on the option parameters in the command line according to the specified parameter list, and nothing more. After this processing, it is relatively simple to parse through the code yourself. Therefore, in the above code sample, there is only one line that actually involves the use of getopt, and the rest of the code is based on the rearranged parameters of getopt, which can be further analyzed by itself.

In this example, option arguments and non-option arguments are not in order, so first tell the getopt command which arguments to parse:

getopt -o 'u:p:n:vl::' -l 'username:,password:,port:,verbose,log-level::' -- "$@"

Parameter rules:

  • The -o parameter specifies the terminal parameter format, and the -l parameter specifies the corresponding long parameter
  • Colon : rules are basically the same as getopts rules. The difference is that the default value parameter is followed by two colons ::
  • For the default value option, there must be no spaces between the short parameter formal parameter name and the value, and the long parameter formal parameter name and value need to be connected with an equal sign.=
Leave a Reply