[Linux] getopts optional parameters_Bash tips: Introducing the usage of getopts built-in command parsing option parameters

1 Overview

In the Linux bash shell, there is a built-in getopts command that can handle option parameters starting with '-'. This article explains the usage of getopts command in detail through multiple examples.

Introduction to getopts command
When executing commands on the bash shell, some option parameters are often used to specify different operations. For example, the -l, -a options of the ls command, etc.

When we write a shell script, we can also customize some option parameters and use bash's getopts built-in command to parse the option parameters.

Check out the English description of the getopts built-in command in man bash as follows:

getopts optstring name [args]
getopts is used by shell procedures to parse positional parameters.

optstring contains the option characters to be recognized; if a character is followed by a colon, the option is expected to have an argument, which should be separated from it by white space.


Each time it is invoked, getopts places the next option in the shell variable name, initializing name if it does not exist, and the index of the next argument to be processed into the variable OPTIND.

When the end of options is encountered, getopts exits with a return value greater than zero.
OPTIND is set to the index of the first non-option argument, and name is set to ?.

Note: getopts 是 bash 的内置命令。对于 bash 内置命令来说,不能用 man 命令查看它们的帮助说明.
To view, use the help command. You can also search for the command name in man bash to view the corresponding instructions.

$ man getopts

No manual entry for getopts

$ help getopts

getopts: getopts optstring name [arg]

Parse option arguments.

As you can see, man getopts prompts that the description of the getopts command cannot be found, while help getopts prints its description.

In addition, 有一个 getopt 外部命令也可以解析命令选项,名称比 getopts 少了一个 s,用法也有所差异,不要把这两个命令搞混了.

2. Detailed explanation of commands

getopts optstring name [args]

Based on getopts optstring name [args]this command format, the meaning of each parameter of the getopts command is explained as follows.

optstringparameter:

  • Specifies a list of supported option parameters, one character for each option.
  • If the character is followed by a colon: then the option is expected to be followed by an argument, separated by a space.
  • Colon: and question mark? cannot be used as options, that is: and? are special keywords.
Option content illustrate
       : If optsring starts with:, it indicates silent mode and ignores general error messages.
      s Valid options and not followed by parameter values
      s: Valid options and must be followed by parameter values

Complete usage example code1, saved as ./1-4.sh:

#!/bin/bash
 
#input paramters index
echo "OPTIND starts at $OPTIND"
#get paramters
while getopts ":pq:" optname
 do
 case "$optname" in
        "p")
          echo "Option $optname is specified"
          ;;
        "q")
          echo "Option $optname has value $OPTARG"
          ;;
        "?")
          echo "Unknown option $OPTARG"
          ;;
        ":")
          echo "No argument value for option $OPTARG"
          ;;
        *)
          # Should not occur
          echo "Unknown error while processing options"
          ;;
 esac
 echo "OPTION is now $OPTIND"
done

For example, a valid optstring parameter value is "hi:".
Then -h is an option; -i is also an option.
Since i is followed by a colon:, a parameter must be provided when entering the -i option, such as -i insert, etc.
If no parameter is provided after -i during actual execution, the getopts command will report an error.

Note : The option list of the optstring parameter does not contain the - character, but when the option parameters are actually entered, the getopts command requires the option parameters to start with -, otherwise an error will be reported.

Taking the above example, -h is an option, but h is not a valid option (although h is not a valid option, it will not report an error).

2.1 name

nameThe parameter is used to save the parsed option name. 每调用一次 getopts 命令,它只解析一个选项,并把解析的值存入 name 变量中.
The parsed value does not contain the - character.

For example, after parsing the -h option, the value of the name variable is the character h.
The name of the variable is not required to be only a name string, but can also be other legal variable names, such as opt, arg, etc.

If you want to parse multiple options, you need to execute the getopts command multiple times in a while or for loop to parse the parameter options one by one until the parsing is completed.
解析完毕,getopts 命令会返回 false,从而退出循环.

If the provided option is not in the list specified by optstring, name 的值会被设成问号 ?.
However, the getopts command still returns true and no error is reported.

See the complete example above, this is what Case has? The reason for the number

2.2 args

[args]is an optional parameter used to specify the source of option parameters.
The getopts command parses the parameters provided by positional parameters by default, such as $1, $2, ..., etc.

If the args argument is provided, option arguments are parsed from args and no longer from positional arguments. That is, the content of the for loop will come from the specified item, not all input parameters.

  • That is to say, when the getopts command is executed in a shell script 直接, the option parameters it parses by default are the parameters provided when executing the script.
    For example, if there is a testgetopts.sh script, then execute ./testgetopts.sh -a -b the command and getopts will parse the -a and -b options.

  • If you are 函数内executing the getopts command, the option parameters it parses are the parameters provided when calling the function.
    For example, there is a test_getopts function, which calls the getopts command. Then execute the test_getopts -a -b statement, and the getopts command will parse the -a and -b options.

  • If the args argument is provided, the getopts command instead parses the options contained in the args argument.
    For example, when executing args="-a -b"; getopts "ab" opt $argsthe statement, the getopts command parses the "-a -b" string specified by the args variable. If executed ./testgetopts.sh -a -b -c, -c will be ignored.

2.3 OPTARG

OPTARGIt is a global variable used by the getopts command to save the parsed parameter value after the colon option.
For example, when parsing the -i insert option mentioned above, the value of OPTARG is insert.

2.4 OPTING

OPTINDIt is a global variable used by the getopts command to save the next parameter index to be parsed.
When starting a new shell, the default value of OPTIND is 1. When the getopts command is called once, the value of OPTIND is increased by 1.
If an argument is provided after an option with a colon, the value of OPTIND is increased by 2.
After the getopts command has parsed all parameters, the shell will not automatically reset OPTIND to 1.

If you want to parse different option parameters in the same shell script, you need to manually assign a value of 1 to OPTIND, otherwise unexpected options will be parsed.
The testgetopts.sh script will be used as an example later.

2.5 Return value of getopts command

Check the return value of the getopts command in man bash as follows:

getopts returns true if an option, specified or unspecified, is found.
It returns false if the end of options is encountered or an error occurs.

As you can see, 即使提供不支持的选项,getopts 命令也是返回true.

getopts will return false when all options have been parsed, and will also return false when an error is encountered.
The following errors may occur:

  • Option does not start with -
  • An option with a colon requires an argument, but no argument was provided.

What is the use of this return value? We see code1 above, generally used in while loops:


while getopts ":pq:" optname    //这里说明只接受 pg作为有效参数,且p不要求value,q必须带value

During the loop, if a false condition appears, the loop will be terminated. Let’s verify:

This is a fully qualified input parameter:

$./1-4.sh  -p -q 12    //这是完全符合条件的入参
OPTIND starts at 1
Option p is specified    //p参数被迭代出来
OPTION is now 2
Option q has value 12      q参数被迭代出来
OPTION is now 4

Let’s try deliberately adding a non-existent input parameter -m:

./1-4.sh  -p -m -q 12                  //在p q之间我们加入 -m,注意m前有-
OPTIND starts at 1
Option p is specified
OPTION is now 2
./1-4.sh: illegal option -- m        //m入参不在允许的范围内,但仍返回true,得以让while循环体继续,被转为 ?,进入case的?号分支
Unknown option
OPTION is now 3
Option q has value 12         //q仍然被打印,说明-m返回的是true,得以让while循环体继续
OPTION is now 5

This time, let’s try adding m. Note, without -:

 ./1-4.sh  -p m -q 12
OPTIND starts at 1
Option p is specified
OPTION is now 2      
          //这里么有q,说明  m 被赋返回值 false,导致循环终止了

3. testgetopts.sh script example

The following uses a testgetopts.sh script as an example to illustrate the usage of the getopts command. The content is as follows:

#!/bin/bash
    
function test_getopts_ab()
{
    
    
    local opt_ab
    while getopts "ab" opt_ab; do        #函数内调用
        echo $FUNCNAME: $OPTIND: $opt_ab
    done
}
    
echo Before Call test_getopts_ab: OPTIND: $OPTIND ++
test_getopts_ab "-a" "-b"
echo After Call test_getopts_ab: OPTIND: $OPTIND --     #函数外  打印OPTIND,是3,说明是累加的,全局变量
    
while getopts "ef" opt_ef; do     #脚本直接调用
    echo $OPTIND: $opt_ef
done
    
OPTIND=1
echo Reset OPTIND to: $OPTIND
    
number=6;
while getopts "s:g" opt_sg; do
    case $opt_sg in
        g) echo $number ;;
        s) number=$OPTARG ;;
        ?) echo "unknown option: $opt_sg" ;;
    esac
done

This script first calls the getopts command in the test_getopts_ab function to parse the incoming "-a" and "-b" options.
Then call the getopts command to parse the command line option parameters passed in when executing the script.
Finally, reset the value of OPTIND and re-parse the command line option parameters.

Take the getopts "ab" opt_ab statement, "ab" corresponds to the optstring parameter mentioned above, and the options it supports are -a and -b.
opt_ab corresponds to the name variable name mentioned above, saves the parsed options, and does not contain the - character.

Executing this script results in the following:

$ ./testgetopts.sh -s 7 -g -f

Before Call test_getopts_ab: OPTIND: 1 ++

test_getopts_ab: 2: a

test_getopts_ab: 3: b

After Call test_getopts_ab: OPTIND: 3 --

./testgetopts.sh: illegal option -- g

4: ?

5: f

Set OPTIND to: 1

7

./testgetopts.sh: illegal option -- f

unknown option: ?

  • It can be seen that after the test_getopts_ab function parses the option parameters, the value of OPTIND printed outside the function is 3.

  • After calling the getopts command again, the OPTIND value does not start from 1, but starts from 3. The third parameter -g passed to testgetopts.sh is obtained, 跳过了前面的 -s 7two parameters.

    This is not the expected result. Normally, the expectation is to start parsing from the first option argument.
    Since the getopts "ef" opt_ef statement does not support the -g option, an error message is printed and opt_ef is assigned a question mark?.

  • After manually resetting the OPTIND value to 1, getopts "s:g" opt_sg can parse starting from the first option argument.
    First process the -s 7 option, getopts assigns 7 to OPTARG, and then assigns the value of OPTARG to the number variable in the script.

    Then continue processing the -g option and print out the value of the number variable.

    Finally, the -f option is processed. This option is not supported, the value of opt_sg is set to a question mark?, and the "unknown option" information is printed.

    After all options have been processed, getopts returns false and exits the while loop.

OPTIND is a global parameter

4. Wrong judgment

The getopts command will return false when it finishes processing the option parameters or encounters an error 不能通过判断返回值来确认是否遇到了错误.

When getopts is called in a while or for loop, the value of OPTIND can be used to determine whether getopts encountered an error. If the value of OPTIND minus 1 is not equal to the number of parameters passed in, then an error has been encountered and the loop has been exited early.

When getopts processes option parameters, the value of OPTIND starts at 1 and is incremented.
After processing all parameters, OPTIND points to the last parameter, which is equivalent to adding 1 to the number of all parameters.
Therefore, the value of OPTIND minus 1 should be equal to the number of parameters passed in.

Bash's $# expression can obtain the number of parameters passed in. If the two values ​​​​are not equal, then getopts has not parsed the option parameters, that is, it encountered an error and exited the loop early.

Suppose there is a test.sh script with the following content:

#!/bin/bash
while getopts "abcd" arg; do
    echo $OPTIND: $arg
done
    
echo OPTIND: $OPTIND. $#: $#
if [ "$(($OPTIND - 1))" != "$#" ]; then
    echo Error occurs.
fi

Passing in different option parameters, the results of executing the script are as follows:

$ ./test.sh -a -b -c
2: a
3: b
4: c
OPTIND: 4. $#: 3

$ ./test.sh -a -b
2: a
3: b
OPTIND: 3. $#: 2

$ ./test.sh -a b
2: a
OPTIND: 2. $#: 2
Error occurs.

It can be seen that when the end of the option is encountered normally, the value of the OPTIND variable is the number of options plus 1.
When an error is encountered, the value of the OPTIND variable is not the number of options plus one.
So when the value of the OPTIND variable is minus 1 and is not equal to $#, it means that an error has been encountered.

5. The impact of executing the script multiple times through source on OPTIND

The script called through the source command is run under the current shell. Since the shell will not automatically reset the value of OPTIND, if the script to be called uses the getopts command to parse the option parameters, otherwise the value of OPTIND will not increase from 1 and will be obtained 在每次调用 getopts 之前,一定要手动重置 OPTIND 为 1. Unexpected option parameter value.

Suppose there is a test.sh script with the following content:

#!/bin/bash

echo $#: $#, $@: $@, OPTIND: $OPTIND

getopts "abc" opt

echo $?, $opt

Execute the script without using the source command and using the source command respectively. The results are as follows:

$ ./test.sh -a

$#: 1, $@: -a, OPTIND: 1

0, a

$ ./test.sh -b

$#: 1, $@: -b, OPTIND: 1

0, b

$ source ./test.sh -a

$#: 1, $@: -a, OPTIND: 1

0, a

$ source ./test.sh -b

$#: 1, $@: -b, OPTIND: 2

1, ?

It can be seen that the output results of executing the ./test.sh -a command and the ./test.sh -b command are normal.
The result of executing the source ./test.sh -a command is also normal.
But then execute the source ./test.sh -b command, before calling getopts, the value of OPTIND is printed out to be 2, and the second option parameter needs to be obtained.
Since the second option parameter is not provided, the option parameter value obtained is a question mark?, and the return value of the getopts command obtained using $? is 1, and an error is reported during execution.

That is, if a script uses the getopts command and the script is executed using the source command, the script needs to manually set the value of the OPTIND variable to 1, otherwise it will encounter the above exception.

When we write a script ourselves and configure alias in the .bashrc file, use the source command to execute the script, such as the following settings:

alias c=‘source quickcd.sh’

When the quickcd.sh script uses the getopts command and does not reset the value of OPTIND, if the c command is executed multiple times, the exception described above will be encountered.

reference

getopts Optional Parameters_Bash Tips: Introducing the usage of getopts built-in command to parse option parameters

Guess you like

Origin blog.csdn.net/m0_45406092/article/details/133358134