Contents

解析命令行选项

1. 概述

作为 Linux 用户,我们经常使用各种命令行实用程序和脚本。开发脚本时的常见任务之一是解析命令行选项。这些选项可以很短也可以很长。

在本教程中,我们将使用bashgetopts 函数和*getopt 实用程序来解析命令行选项。*

2. 使用getopts解析简短的命令行选项

在 Bash中,我们可以使用短命令行选项和长命令行选项。短选项以单个*连字符 (-)字符开头,后跟单个字母数字字符,而长选项以双连字符 (-)*字符开头,后跟多个字符。

我们可以指示*ls *命令显示隐藏文件:

$ ls -a
.  ..  hello.txt
$ ls --all
.  ..  hello.txt

在上面的例子中:

  • -a 代表空头选项
  • –all 代表长选项

**要解析简短的命令行选项,我们可以使用bash的内置函数getopts。**它将位置参数解析为选项。

2.1. getopts语法

getopts函数的语法是:

getopts optstring opt [arg ...]

在上述函数中:

  • optstring表示支持的选项。如果后面有一个冒号 (:) ,则该选项需要一个参数。例如,如果选项c需要一个参数,那么它将在optstring中表示为c:
  • 当选项具有关联的参数时,getopts会将参数作为字符串存储在OPTARG shell 变量中。例如,传递给选项c 的参数将存储在OPTARG变量中。
  • opt包含已解析的选项。

在接下来的部分中,当我们看到它们在行动中时,这些概念将变得清晰。

2.2. 脚本中的示例用法

让我们创建一个简单的 shell 脚本来看看它的用法:

#!/bin/bash
while getopts 'abc:h' opt; do
  case "$opt" in
    a)
      echo "Processing option 'a'"
      ;;
    b)
      echo "Processing option 'b'"
      ;;
    c)
      arg="$OPTARG"
      echo "Processing option 'c' with '${OPTARG}' argument"
      ;;
   
    ?|h)
      echo "Usage: $(basename $0) [-a] [-b] [-c arg]"
      exit 1
      ;;
  esac
done
shift "$(($OPTIND -1))"

让我们执行脚本并观察输出:

$ chmod +x parse-command-line-args.sh
$ ./parse-command-line-args.sh -a 
Processing option 'a' 
$ ./parse-command-line-args.sh -c test-value
Processing option 'c' with 'test-value' argument 
$ ./parse-command-line-args.sh -ab 
Processing option 'a'
Processing option 'b'

2.3. getopts中的错误报告

getopts函数在两种情况下报告错误——首先,使用无效选项时,其次,未提供参数时:

  • 如果提供了无效选项,则opt变量包含问号*(?)字符*
  • 如果未提供必需的参数,则opt变量包含冒号*(:)字符*

我们可以捕获这两种错误场景并向用户显示适当的错误消息。让我们修改脚本来处理这些场景:

#!/bin/bash
while getopts ':abc:h' opt; do
  case "$opt" in
    a)
      echo "Processing option 'a'"
      ;;
    b)
      echo "Processing option 'b'"
      ;;
    c)
      arg="$OPTARG"
      echo "Processing option 'c' with '${OPTARG}' argument"
      ;;
    h)
      echo "Usage: $(basename $0) [-a] [-b] [-c arg]"
      exit 0
      ;;
    :)
      echo -e "option requires an argument.\nUsage: $(basename $0) [-a] [-b] [-c arg]"
      exit 1
      ;;
    ?)
      echo -e "Invalid command option.\nUsage: $(basename $0) [-a] [-b] [-c arg]"
      exit 1
      ;;
  esac
done
shift "$(($OPTIND -1))"

现在,我们将执行脚本并检查错误消息:

$ ./parse-command-line-args.sh -c
option requires an argument.
Usage: parse-command-line-args.sh [-a] [-b] [-c arg]
$ ./parse-command-line-args.sh -e
Invalid command option.
Usage: parse-command-line-args.sh [-a] [-b] [-c arg]

**请注意,我们也更新了optstring 现在它以冒号 (:)字符开头,它禁止默认错误消息。**除此之外,我们可以使用OPTERR环境变量来改变错误报告行为。当OPTERR变量设置为零时, getopts函数禁用错误报告。

3. 使用getopt解析长命令行选项

有时,使用长命令行选项来提高可读性很方便。但是,getopts仅支持简短的命令行选项。我们可以使用 GNU 的getopt命令来解析长的命令行选项

#!/bin/bash
VALID_ARGS=$(getopt -o abg:d: --long alpha,beta,gamma:,delta: -- "$@")
if [[ $? -ne 0 ]]; then
    exit 1;
fi
eval set -- "$VALID_ARGS"
while [ : ]; do
  case "$1" in
    -a | --alpha)
        echo "Processing 'alpha' option"
        shift
        ;;
    -b | --beta)
        echo "Processing 'beta' option"
        shift
        ;;
    -g | --gamma)
        echo "Processing 'gamma' option. Input argument is '$2'"
        shift 2
        ;;
    -d | --delta)
        echo "Processing 'delta' option. Input argument is '$2'"
        shift 2
        ;;
    --) shift; 
        break 
        ;;
  esac
done

在上面的脚本中:

  • -o选项代表简短的命令行选项
  • –long选项代表长的命令行选项

让我们执行脚本并观察输出:

$ chmod +x parse-long-command-line-args.sh 
$ ./parse-long-command-line-args.sh -a
Processing 'alpha' option
$ ./parse-long-command-line-args.sh --alpha
Processing 'alpha' option
$ ./parse-long-command-line-args.sh --delta test-value
Processing 'delta' option. Input argument is 'test-value'
$ ./parse-long-command-line-args.sh -g test-value
Processing 'gamma' option. Input argument is 'test-value'