带帮助参数的 shell getopt

带帮助参数的 shell getopt

我正在准备一个脚本getopt。我想添加帮助部分。因此,如果他们使用--help-h应该执行该函数(只需打印说明)并返回它。

示例代码:


log_type='unset'
state='unset'
date='unset'
help='unset'


mode="$1"
usage()
{
  echo "Usage: LogRotator [ -t | --log_type  - Allowed values: [access error] ] 
                          [ -s | --state - Allowed values: [archive or backup] ]
                          [ -d | --date 1-10-2020] 
                          [ -h | --help]

        Modes:
            1) list - list the files
            2) restore  - restore the files"
  exit 2
}


ARGUMENT_LIST=(
    "log-type"
    "state"
    "date"
)



# read arguments
opts=$(getopt \
    --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")",help \
    --name "$(basename "$0")" \
    --options "" \
    -- "$@"
)

VALID_ARGUMENTS=$?
if [ "$VALID_ARGUMENTS" != "0" ]; then
  usage
fi

eval set --$opts

while [[ $# -gt 0 ]]; do
    case "$1" in
        -t | --log-type)
            log_type=$2
            shift 2
            ;;

        -s | --state)
            state=$2
            shift 2
            ;;

        -d | --date)
        date=$2
        shift 2
        ;;

        -h | --help)
        help=1
        shift 
        ;;
        *)
        break
        ;;
    esac
done

if [[ "$help" == 1 ]]
then
    usage
fi

上面的脚本工作正常,但我添加了一个单独的部分来检查和调用使用函数,我不确定这是否是一个好的做法。

另外,另一个问题是,它不接受单个-标志(如 -h -t)

我尝试添加-o tsdh但没有成功。

预期输出:

./script -h

Usage: LogRotator [ -t | --log_type  - Allowed values: [access error] ] 
                          [ -s | --state - Allowed values: [archive or backup] ]
                          [ -d | --date 1-10-2020] 

        Modes:
            1) list - list the files
            2) restore  - restore the files

答案1

我将其写为代码审查:

首先,您没有指定 shebang。如果没有 shebang,脚本将由sh.您的代码不符合sh语法。语法最相似的 shell 是zsh.不过,如果不是未加引号的$opts,它也可以在 ksh93 和 bash 中工作。我想它是为 bash 设计的,因为zsh会有更好的方法来编写它。

所以在这里:

#! /bin/bash -

或者:

#! /usr/bin/env bash

支持bash不在/bin.

log_type='unset'
state='unset'
date='unset'
help='unset'

在这里,如果您使用特定字符串作为默认值,则将无法消除用户未指定选项但值为 的情况unset

在这里,我只想做

unset -v log_type state date help

虽然对于布尔值,我更喜欢help=false.

mode="$1"

在这里,您将第一个参数存储在 中$mode,但不检查它是否存在,也不将其从参数列表中删除,这意味着getopt也会收到它!

或许:

  case $1 in
    (list | restore) mode=$1; shift;;
    (*) usage;;
  esac

(在函数声明之后usage)。

usage()
{
  echo "Usage: LogRotator [ -t | --log_type  - Allowed values: [access error] ] 
                          [ -s | --state - Allowed values: [archive or backup] ]

请注意,虽然这些[ -t[ -s在脚本的源代码中对齐,但由于缩进,它们不会出现在输出中。另外,您将像此处那样对脚本的名称进行硬编码LogRotator,但稍后使用basenameof 。$0另外,该使用消息应该发送到 stderr,因此:

PROGNAME=${0##*/}

usage() {
  cat << EOF >&2
Usage: $PROGNAME ...
EOF
                          [ -d | --date 1-10-2020] 

1-10-2020可能是最糟糕的日期格式。首先它是模棱两可的。大多数人会将其理解为 10 月 1 日,但在北美部分地区,则会将其理解为 1 月 10 日。此外,这些字符串按时间顺序排序与按词法排序不同(即使在您对字段重新排序后,因为这些部分不是用零填充的)。

日期有一种国际格式。 2020-10-01 将成为标准,被大多数人和公用事业公司认可,并且按词汇顺序排序与按时间顺序排序相同。

[...]

ARGUMENT_LIST=(
    "log-type"
    "state"
    "date"
)

最好保留所有大写变量环境变量。

# read arguments
opts=$(getopt \
    --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")",help \

在这里,您将附加:,到 的所有元素$ARGUMENT_LIST,因此将得到log-type:,state:,date:,,help

    --name "$(basename "$0")" \

应该是"$(basename -- "$0"}"或者${0##*/}这里。这"$PROGNAME"是我们之前定义的。

    --options "" \

这是针对单字符选项的,因此您需要在此处指定它们:

  --options hs:d:t:
    -- "$@"
)

VALID_ARGUMENTS=$?
if [ "$VALID_ARGUMENTS" != "0" ]; then

if检查命令是否成功。这就是它的作用。

所以就:

   if 
     ! opts=$(
       ...
     )
   then
     usage
   fi

要不就:

   opts=$(...) || usage

这里。

  usage
fi

eval set --$opts

不加引号的参数扩展会调用 split+glob ,这在这里没有意义。另外,您需要将其--与此处的其余部分分开。就是set -- <contents-of-$opts>你想被评估为 shell 代码,所以:

   eval "set -- $opts"
while [[ $# -gt 0 ]]; do
    case "$1" in
        -t | --log-type)
            log_type=$2

您需要根据此处允许的设置检查提供的值,以警告用户是否使用-t blah -t error.您还可以警告用户仅考虑最后指定的类型。

            shift 2
            ;;

        -s | --state)
            state=$2
            shift 2
            ;;

        -d | --date)
        date=$2

注意缩进。一致的缩进使代码更易于阅读并有助于避免一些错误。

        shift 2
        ;;

        -h | --help)
        help=1
        shift 
        ;;
        *)
        break

应该shift; break在这里,因为getopt会添加一个--来告诉您选项结束的位置。

        ;;
    esac
done

此时,您可能需要检查是否有更多参数可用,如果不符合预期则报告错误:

  [ "$#" -eq 0 ] || usage
if [[ "$help" == 1 ]]
then
    usage
fi

如果您使用了help=false/ help=true,那么那就是:

  if "$help"; then
    usage
  fi

答案2

我通过在 中添加简短选项来更正您的脚本getopt,请注意,:在每个之后opt意味着该选项需要一个参数:

#!/bin/bash
log_type='unset'
state='unset'
date='unset'
help='unset'


mode="$1"
usage()
{
  echo "Usage: LogRotator [ -t | --log_type  - Allowed values: [access error] ] 
                          [ -s | --state - Allowed values: [archive or backup] ]
                          [ -d | --date 1-10-2020] 
                          [ -h | --help]

        Modes:
            1) list - list the files
            2) restore  - restore the files"
  exit 2
}


ARGUMENT_LIST=(
    "log-type"
    "state"
    "date"
)



# read arguments
opts=$(getopt \
    -o t:s:d:h \
    --longoptions "$(printf "%s:," "${ARGUMENT_LIST[@]}")",help \
    --name "$(basename "$0")" \
    -- "$@"
)

VALID_ARGUMENTS=$?
if [ "$VALID_ARGUMENTS" != "0" ]; then
  usage
fi

eval set -- $opts

while [[ $# -gt 0 ]]; do
    case "$1" in
        -t | --log-type)
            log_type=$2
            shift 2
            ;;

        -s | --state)
            state=$2
            shift 2
            ;;

        -d | --date)
        date=$2
        shift 2
        ;;

        -h | --help)
        help=1
        shift
        ;;
        *)
        break
        ;;
    esac
done

if [[ "$help" == 1 ]]
then
    usage
fi

相关内容