getopts中没有指定选项时执行默认选项

getopts中没有指定选项时执行默认选项

我按照教程进行操作这里学习如何使用getopts。我能够执行用户正确提供的所有选项。但现在我想在没有提供任何选项时执行默认选项。

例如:

while getopts ":hr" opt; do
    case $opt in
        h )
            show_help;
            exit 1
            ;;
        r )
          echo "Default option executed"
          ;;
    esac
done

因此,如果用户提供 或-h-r则应执行相应的命令(实际上确实如此),但如果未提供这些选项,-r则应默认执行。有办法实现这一点吗?

更新

我尝试了cas's建议并将其纳入*)我的getopts功能中,但似乎没有发生任何事情。

while getopts ":hr" opt; do
    case $opt in
        h )
            show_help;
            exit 1
            ;;
        r )
          echo "Default option executed"
          ;;

        \? )
          echo error "Invalid option: -$OPTARG" >&2
          exit 1
          ;;

        : )
          echo error "Option -$OPTARG requires an argument."
          exit 1
          ;;

        * )
          echo "Default option executed"
          ;;
    esac
done

这段代码有什么问题吗?

答案1

向语句添加默认选项不会有帮助,因为如果没有要解析的选项,case则不会执行该语句。getopts您可以看到它使用 shell 变量处理了多少个选项OPTIND。从help getopts

Each time it is invoked, getopts will place 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 shell
variable OPTIND.  OPTIND is initialized to 1 each time the shell or
a shell script is invoked.

因此,如果OPTIND为 1,则不处理任何选项。在循环后添加以下内容while

if (( $OPTIND == 1 )); then
   echo "Default option"
fi

答案2

while当没有提供选项时,Bash 的 getopts 将退出循环,将 $opt 设置为“?”。要确定脚本中的这种情况,请在循环if后添加一个子句while,类似于:

if [ "$opt" = "?" ]
then
  echo "Default option executed (by default)"
fi

作为参考,请参阅Bourne Shell 内置函数

答案3

使用getopts循环根据传递的参数设置变量。然后对这些变量采取行动:

#!/bin/sh

# Defaults:
do_help=0
do_r=0

while getopts "hr" opt; do
    case $opt in
        h) do_help=1 ;;
        r) do_r=1    ;;
        *) echo 'Error in command line parsing' >&2
           exit 1
    esac
done

if [ "$do_help" -eq 1 ]; then
    show_help
    exit
fi

printf 'Default option executed (r=%d)\n' "$do_r"

我选择让代码在-h使用时成功退出(除非show_help失败),而不是使用非零退出状态(寻求帮助不是错误)。

运行它:

$ sh script.sh -r
Default option executed (r=1)
$ sh script.sh
Default option executed (r=0)
$ sh script.sh -h
script.sh[24]: show_help: not found

这样做的好处是将命令行解析代码与脚本的其余逻辑分开。

它还允许您在循环后进行基本的健全性检查,同时保持实际的解析循环简短。例如:

# command line parsing loop above here

if [ "$do_help" -eq 1 ] && [ "$do_r" -eq 1 ]; then
    echo 'Options -h and -r are mutually exclusive' >&2
    exit 1
fi

# code that acts on user-supplied options below

答案4

据我所知, r 并不期待争论。从逻辑上讲,无论发生什么,r 都会以相同的方式执行。

我会将与 r 相关的命令从 getopts 子句中取出并让它执行。我相信这足以满足您的要求。换句话说,将 echo 语句放在“done”语句之后。

如果您希望出于兼容性或其他原因,可以将 r 作为存根保留在 getopts 中。

您还可以添加设置为零的变量作为开关。一旦选择了 r 以外的任何选项,就会有一行将该变量更改为 1。在完成语句之后,您可以编写“如果变量等于 0,则执行默认命令”。


我想我最喜欢Cas的回答。我想发表评论,但我没有特权。我会以他的想法为基础。这与 Cas 提出的相同,但你只有一个命令(所以你不会有两个相同的命令并在将来犯错误),并且它会给你除了 - 之外还使用它的可能性H。

DEF="Default command executed"
while getopts ":hr" opt;
   do case $opt in 
     h) show_help; 
        exit 1 ;; 
     r) echo "$DEF" ;; 
     *) echo "$DEF" ;; 
  esac
done

相关内容