getopts的可选选项参数

ive*_*son 34 bash getopt getopts

while getopts "hd:R:" arg; do
  case $arg in
    h)
      echo "usgae" 
      ;;
    d)
      dir=$OPTARG
      ;;
    R)
      if [[ $OPTARG =~ ^[0-9]+$ ]];then
        level=$OPTARG
      else
        level=1
      fi
      ;;
    \?)
      echo "WRONG" >&2
      ;;
  esac
done
Run Code Online (Sandbox Code Playgroud)
  • level是指参数-R,dir是指参数-d

  • 当我输入 ./count.sh -R 1 -d test/它正确的工作

  • 当我输入./count.sh -d test/ -R 1它正确的工作

  • 但我想在输入./count.sh -d test/ -R或输入时使其工作./count.sh -R -d test/

这意味着我想要-R一个默认值,命令序列可以更灵活.

And*_*ler 22

错误.实际上getopts确实支持可选参数!从bash手册页:

If  a  required  argument is not found, and getopts is not silent, 
a question mark (?) is placed in name, OPTARG is unset, and a diagnostic
message is printed.  If getopts is silent, then a colon (:) is placed in name 
and OPTARG is set to the option character found.
Run Code Online (Sandbox Code Playgroud)

当手册页显示"无声"时,它表示无声错误报告.要启用它,optstring的第一个字符必须是冒号:

while getopts ":hd:R:" arg; do
    # ...rest of iverson's loop should work as posted 
done
Run Code Online (Sandbox Code Playgroud)

由于Bash的getopt无法识别--结束选项列表,因此-R在最后一个选项时可能无效,后跟一些路径参数.

PS:传统上,getopt.c使用两个冒号(::)来指定可选参数.但是,Bash使用的版本没有.

  • 不,你错了.`./count.sh -R -d test /`不起作用,因为`-d`被视为`-R`的参数(它根本不是可选的). (8认同)
  • 这个答案充其量是误导性的.正如@calandoa指出的那样,任何带有"可选"参数的选项只有"有效"才能给出最后一个选项.否则,它将使用下一个选项作为其参数.例如,在这种用法中`./count.sh -R -d test /`' - R'将'-d'作为其参数,' - d'不被识别为选项.我只是重述已经说过的话(@calandoa),因为这个错误的答案有20个净值. (5认同)

tri*_*eee 16

getopts并不真的支持这一点; 但是写自己的替代品并不难.

while true; do
    case $1 in
      -R) level=1
            shift
            case $1 in
              *[!0-9]* | "") ;;
              *) level=$1; shift ;;
            esac ;;
        # ... Other options ...
        -*) echo "$0: Unrecognized option $1" >&2
            exit 2;;
        *) break ;;
    esac
done
Run Code Online (Sandbox Code Playgroud)

  • **@ Rohit**请注意**Andreas Spindler**答案在大多数方面都是错误的,如下面评论中所述. (3认同)

Ako*_* Cz 10

我同意tripleee,getopts不支持可选参数处理.

我已经解决的妥协解决方案是使用相同选项标志的大写/小写组合来区分采用参数的选项和不参数的选项.

例:

COMMAND_LINE_OPTIONS_HELP='
Command line options:
    -I          Process all the files in the default dir: '`pwd`'/input/
    -i  DIR     Process all the files in the user specified input dir
    -h          Print this help menu

Examples:
    Process all files in the default input dir
        '`basename $0`' -I

    Process all files in the user specified input dir
        '`basename $0`' -i ~/my/input/dir

'

VALID_COMMAND_LINE_OPTIONS="i:Ih"
INPUT_DIR=

while getopts $VALID_COMMAND_LINE_OPTIONS options; do
    #echo "option is " $options
    case $options in
        h)
            echo "$COMMAND_LINE_OPTIONS_HELP"
            exit $E_OPTERROR;
        ;;
        I)
            INPUT_DIR=`pwd`/input
            echo ""
            echo "***************************"
            echo "Use DEFAULT input dir : $INPUT_DIR"
            echo "***************************"
        ;;
        i)
            INPUT_DIR=$OPTARG
            echo ""
            echo "***************************"
            echo "Use USER SPECIFIED input dir : $INPUT_DIR"
            echo "***************************"
        ;;
        \?)
            echo "Usage: `basename $0` -h for help";
            echo "$COMMAND_LINE_OPTIONS_HELP"
            exit $E_OPTERROR;
        ;;
    esac
done
Run Code Online (Sandbox Code Playgroud)


小智 7

这实际上非常简单.只需在R之后删除尾部冒号并使用OPTIND

while getopts "hRd:" opt; do
   case $opt in
      h) echo -e $USAGE && exit
      ;;
      d) DIR="$OPTARG"
      ;;
      R)       
        if [[ ${@:$OPTIND} =~ ^[0-9]+$ ]];then
          LEVEL=${@:$OPTIND}
          OPTIND=$((OPTIND+1))
        else
          LEVEL=1
        fi
      ;;
      \?) echo "Invalid option -$OPTARG" >&2
      ;;
   esac
done
echo $LEVEL $DIR
Run Code Online (Sandbox Code Playgroud)

count.sh -d test

测试

count.sh -d test -R

1测试

count.sh -R -d test

1测试

count.sh -d test -R 2

2测试

count.sh -R 2 -d测试

2测试

  • 使用@calandoa的答案修复它可以使其通过所有测试。 (2认同)

cal*_*doa 5

此解决方法定义了不带参数的R(不带“:”),测试了-R之后的任何参数(在命令行上管理最后一个选项),并测试现有参数是否以短划线开头。

# No : after R
while getopts "hd:R" arg; do
  case $arg in
  (...)
  R)
    # Check next positional parameter
    eval nextopt=\${$OPTIND}
    # existing or starting with dash?
    if [[ -n $nextopt && $nextopt != -* ]] ; then
      OPTIND=$((OPTIND + 1))
      level=$nextopt
    else
      level=1
    fi
    ;;
  (...)
  esac
done
Run Code Online (Sandbox Code Playgroud)

  • eval nextopt=\${$OPTIND} 是一个创造性的解决方案,但是 Bash 已经有了用于间接扩展的特殊语法:nextopt=${!OPTIND}。 (8认同)
  • 事实上,这是这里唯一有效的答案!请点赞吧。 (3认同)
  • 受到这个答案的启发(唯一一个真正有效的答案!),我制作了一个简单的函数,可以轻松地多次使用。请参阅我的答案[此处](/sf/answers/4010719541/) (2认同)