如何在 bash 中使用 getopts 的示例

Posted

技术标签:

【中文标题】如何在 bash 中使用 getopts 的示例【英文标题】:An example of how to use getopts in bash 【发布时间】:2013-05-05 04:31:55 【问题描述】:

我想这样调用myscript文件:

$ ./myscript -s 45 -p any_string

$ ./myscript -h  #should display help
$ ./myscript     #should display help

我的要求是:

getopt 在这里获取输入参数 检查-s是否存在,如果不存在则返回错误 检查-s后面的值是45还是90 检查-p是否存在且后面有输入字符串 如果用户输入./myscript -h 或只输入./myscript,则显示帮助

到目前为止,我尝试了这段代码:

#!/bin/bash
while getopts "h:s:" arg; do
  case $arg in
    h)
      echo "usage" 
      ;;
    s)
      strength=$OPTARG
      echo $strength
      ;;
  esac
done

但是使用该代码我得到了错误。如何用 Bash 和 getopt 做到这一点?

【问题讨论】:

选项应该是可选的。如果您需要-s 指定的值,请将其设为位置参数:./myscript 45 anystring @chepner $./myscript -s 45 -p any_string 如果-p 实际上是一个选项,那很好(也就是说,如果它不存在,您的程序可以继续)。在这种情况下,./myscript 45 -p any_string。 (我认为getopt 可以处理混合选项和位置参数,而bash 内置命令getopts 要求将所有位置参数放在选项之后。) 【参考方案1】:
#!/bin/bash

usage()  echo "Usage: $0 [-s <45|90>] [-p <string>]" 1>&2; exit 1; 

while getopts ":s:p:" o; do
    case "$o" in
        s)
            s=$OPTARG
            ((s == 45 || s == 90)) || usage
            ;;
        p)
            p=$OPTARG
            ;;
        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

if [ -z "$s" ] || [ -z "$p" ]; then
    usage
fi

echo "s = $s"
echo "p = $p"

示例运行:

$ ./myscript.sh
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -h
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s "" -p ""
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 10 -p foo
Usage: ./myscript.sh [-s <45|90>] [-p <string>]

$ ./myscript.sh -s 45 -p foo
s = 45
p = foo

$ ./myscript.sh -s 90 -p bar
s = 90
p = bar

【讨论】:

在getopts调用中,为什么有一个前导冒号? “h”后面什么时候有冒号? usage() 真的应该返回 1 吗? @Pithikos 好点。常识告诉我,当通过-h 调用时,它应该返回0,在遇到不存在的标志时,它应该返回&gt;0(为了简单起见,我没有区分这些情况,没有人强迫你在后一种情况下打印使用文本)。不过,即使在-h/--help 上,我也见过总是返回!= 0 的程序。也许我应该更新 sn-p 以防人们将其用作样板(我希望不会)? @A.Danischewski 这是由 (getopts') 设计的,getopts 没有“可选参数”之类的东西。解析器根本无法知道下一个标记是当前选项的参数还是选项本身,因为-p 可能是预期值。如果您绝对知道选项参数不能看起来像另一个有效选项,您可以解决这个问题,是的,但有人可能会说在 POSIX 中未定义可选参数是有原因的。 @user1011471 你是对的!可以这么说,花括号只是帮助bash 词法分析器识别变量。在很多情况下它们是不需要的,而我总是使用它们只是个人编码风格的问题。对我来说,总是使用它们而不是记住关于歧义的解析规则更容易(也更漂亮)。几乎与为什么人们会用 C 风格语言编写 if (foo) bar; 而不是 if (foo) bar; (美学和/或避免愚蠢的错误)的原因相同。【参考方案2】:

原代码的问题在于:

h: 需要不应该的参数,因此将其更改为 h(不带冒号) 要期待-p any_string,您需要将p: 添加到参数列表中

基本上: 在选项之后意味着它需要参数。


getopts 的基本语法是(见:man bash):

getopts OPTSTRING VARNAME [ARGS...]

地点:

OPTSTRING 是带有预期参数列表的字符串,

h - 检查选项-h 没有参数;在不支持的选项上给出错误; h: - 检查选项 -h with 参数;在不支持的选项上给出错误; abc - 检查选项-a-b-c;在不受支持的选项上给出错误;

:abc - 检查选项-a-b-csilences 在不支持的选项上出现错误;

注意:换句话说,选项前面的冒号可以让您处理代码中的错误。如果选项不受支持,变量将包含?,在缺少值的情况下将包含:

OPTARG - 设置为当前参数值,

OPTERR - 指示 Bash 是否应显示错误消息。

所以代码可以是:

#!/usr/bin/env bash
usage()  echo "$0 usage:" && grep " .)\ #" $0; exit 0; 
[ $# -eq 0 ] && usage
while getopts ":hs:p:" arg; do
  case $arg in
    p) # Specify p value.
      echo "p is $OPTARG"
      ;;
    s) # Specify strength, either 45 or 90.
      strength=$OPTARG
      [ $strength -eq 45 -o $strength -eq 90 ] \
        && echo "Strength is $strength." \
        || echo "Strength needs to be either 45 or 90, $strength found instead."
      ;;
    h | *) # Display help.
      usage
      exit 0
      ;;
  esac
done

示例用法:

$ ./foo.sh 
./foo.sh usage:
    p) # Specify p value.
    s) # Specify strength, either 45 or 90.
    h | *) # Display help.
$ ./foo.sh -s 123 -p any_string
Strength needs to be either 45 or 90, 123 found instead.
p is any_string
$ ./foo.sh -s 90 -p any_string
Strength is 90.
p is any_string

请参阅:Small getopts tutorial 在 Bash Hackers Wiki

【讨论】:

将使用函数改为:usage() echo "$0 usage:" &amp;&amp; grep "[[:space:]].)\ #" $0 | sed 's/#//' | sed -r 's/([a-z])\)/-\1/'; exit 0; 。它只在字母选项之前占一个空白字符,从注释中删除 # 并在字母选项之前添加一个“-”,使命令更清晰。 @kenorb:选项前面的冒号不会忽略不受支持的选项,但会消除来自 bash 的错误并允许您在代码中处理它。变量将包含“?”在不支持的选项的情况下和':'在缺失值的情况下。 感谢您提供详细的文档,在我看到这些注释之前无法获得:。我们需要在期望参数的选项中添加: 正是我需要的。谢谢。【参考方案3】:

使用getopt

为什么选择 getopt?

解析详细的命令行参数以避免混淆并阐明我们正在解析的选项,以便命令的读者可以理解正在发生的事情。

什么是 getopt?

getopt 用于分解(解析)命令行中的选项,以便于 shell 程序解析,并检查合法选项。它使用 GNU getopt(3) 例程来执行此操作。

getopt 可以有以下几种选项。

    无价值选项 键值对选项

注意:在本文档中,解释语法时:

[ ] 中的任何内容都是语法/示例中的可选参数。 是占位符,这意味着它应该替换为实际值。

如何使用getopt

语法:第一种形式

getopt optstring parameters

例子:

# This is correct
getopt "hv:t::" -v 123 -t123  
getopt "hv:t::" -v123 -t123  # -v and 123 doesn't have whitespace

# -h takes no value.
getopt "hv:t::" -h -v123


# This is wrong. after -t can't have whitespace.
# Only optional params cannot have whitespace between key and value
getopt "hv:t::" -v 123 -t 123

# Multiple arguments that takes value.
getopt "h:v:t::g::" -h abc -v 123 -t21

# Multiple arguments without value
# All of these are correct
getopt "hvt" -htv
getopt "hvt" -h -t -v
getopt "hvt" -tv -h

这里 h,v,t 是选项,-h -v -t 是在命令行中应该如何给出选项。

    'h' 是一个无值选项。 'v:' 意味着选项 -v 具有价值并且 是强制性选项。 ':' 表示有值。 't::' 意味着 选项 -t 具有值但是可选的。 '::' 表示可选。

在可选参数中,值不能与选项有空格分隔。因此,在“-t123”示例中,-t 是选项 123 是值。

语法:第二种形式

getopt [getopt_options] [--] optstring parameters

这里getopt之后分成五部分

命令本身,即 getopt getopt_options,它描述了如何解析参数。单破折号长选项,双破折号选项。 --,将 getopt_options 与您要解析的选项和允许的短选项分开 在找到 -- 之后立即采用短选项。就像表单优先语法一样。 参数,这些是您传递给程序的选项。您要解析的选项并获取其上设置的实际值。

例子

getopt -l "name:,version::,verbose" -- "n:v::V" --name=Karthik -version=5.2 -verbose

语法:第三种形式

getopt [getopt_options] -o|--options optstring [getopt_options] [--] [parameters]

这里getopt之后分成五部分

命令本身,即 getopt getopt_options,它描述了如何解析参数。单破折号长选项,双破折号选项。 短选项,即 -o 或 --options。就像 Form first 语法,但带有选项“-o”和“--”之前(双破折号)。 --,将 getopt_options 与您要解析的选项和允许的短选项分开 参数,这些是您传递给程序的选项。您要解析的选项并获取其上设置的实际值。

例子

getopt -l "name:,version::,verbose" -a -o "n:v::V" -- -name=Karthik -version=5.2 -verbose

GETOPT_OPTIONS

getopt_options 改变了命令行参数的解析方式。

以下是一些 getopt_options

选项:-l 或 --longoptions

意味着 getopt 命令应该允许多字符选项 认可。多个选项用逗号分隔。

例如,--name=Karthik 是在命令行中发送的长选项。在 getopt 中,长选项的使用类似于

getopt -l "name:,version" -- "" --name=Karthik

由于指定了 name:,该选项应该包含一个值

选项:-a 或 --alternative

意味着 getopt 命令应该允许长选项有一个破折号 '-' 而不是双破折号 '--'。

例如,您可以只使用-name=Karthik 而不是--name=Karthik

getopt -a -l "name:,version" -- "" -name=Karthik

带有代码的完整脚本示例:

#!/bin/bash

# filename: commandLine.sh
# author: @theBuzzyCoder

showHelp() 
# `cat << EOF` This means that cat should stop reading when EOF is detected
cat << EOF  
Usage: ./installer -v <espo-version> [-hrV]
Install Pre-requisites for EspoCRM with docker in Development mode

-h, -help,          --help                  Display help

-v, -espo-version,  --espo-version          Set and Download specific version of EspoCRM

-r, -rebuild,       --rebuild               Rebuild php vendor directory using composer and compiled css using grunt

-V, -verbose,       --verbose               Run script in verbose mode. Will print out each step of execution.

EOF
# EOF is found above and hence cat command stops reading. This is equivalent to echo but much neater when printing out.



export version=0
export verbose=0
export rebuilt=0

# $@ is all command line parameters passed to the script.
# -o is for short options like -v
# -l is for long options with double dash like --version
# the comma separates different long options
# -a is for long options with single dash like -version
options=$(getopt -l "help,version:,verbose,rebuild,dryrun" -o "hv:Vrd" -a -- "$@")

# set --:
# If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters 
# are set to the arguments, even if some of them begin with a ‘-’.
eval set -- "$options"

while true
do
case $1 in
-h|--help) 
    showHelp
    exit 0
    ;;
-v|--version) 
    shift
    export version=$1
    ;;
-V|--verbose)
    export verbose=1
    set -xv  # Set xtrace and verbose mode.
    ;;
-r|--rebuild)
    export rebuild=1
    ;;
--)
    shift
    break;;
esac
shift
done

运行这个脚本文件:

# With short options grouped together and long option
# With double dash '--version'

bash commandLine.sh --version=1.0 -rV
# With short options grouped together and long option
# With single dash '-version'

bash commandLine.sh -version=1.0 -rV

# OR with short option that takes value, value separated by whitespace
# by key

bash commandLine.sh -v 1.0 -rV

# OR with short option that takes value, value without whitespace
# separation from key.

bash commandLine.sh -v1.0 -rV

# OR Separating individual short options

bash commandLine.sh -v1.0 -r -V

【讨论】:

来源:linkedin.com/pulse/… getopt vs getopts .. 跨平台合规性非常不同 虽然我也觉得 GNU getopt 更胜一筹,但它并非内置于 BSD 系统(如 macOS)上,因此如果您的目标是跨平台兼容性,请使用 getopts 您的示例将参数作为单个字符串传递。 getopt "hv:t::" "-v 123 -t123" 如何为您工作? getopt 仅在我将它们作为参数传递时才对我有效:getopt "hv:t::" -v 123 -t123.【参考方案4】:

使用getopt 打包的示例(我的发行版将它放在/usr/share/getopt/getopt-parse.bash 中)看起来涵盖了您的所有情况:

#!/bin/bash

# A small example program for using the new getopt(1) program.
# This program will only work with bash(1)
# An similar program using the tcsh(1) script language can be found
# as parse.tcsh

# Example input and output (from the bash prompt):
# ./parse.bash -a par1 'another arg' --c-long 'wow!*\?' -cmore -b " very long "
# Option a
# Option c, no argument
# Option c, argument 'more'
# Option b, argument ' very long '
# Remaining arguments:
# --> 'par1'
# --> 'another arg'
# --> 'wow!*\?'

# Note that we use `"$@"' to let each command-line parameter expand to a 
# separate word. The quotes around '$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.
TEMP=$(getopt -o ab:c:: --long a-long,b-long:,c-long:: \
              -n 'example.bash' -- "$@")

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around '$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
    case "$1" in
        -a|--a-long) echo "Option a" ; shift ;;
        -b|--b-long) echo "Option b, argument '$2'" ; shift 2 ;;
        -c|--c-long) 
            # c has an optional argument. As we are in quoted mode,
            # an empty parameter will be generated if its optional
            # argument is not found.
            case "$2" in
                "") echo "Option c, no argument"; shift 2 ;;
                *)  echo "Option c, argument '$2'" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done
echo "Remaining arguments:"
for arg do echo '--> '"'$arg'" ; done

【讨论】:

外部命令 getopt(1) 永远不会安全使用,除非你知道它是 GNU getopt,你以 GNU 特定的方式调用它,并且 您确保 GETOPT_COMPATIBLE 不在环境中。改用 getopts(shell 内置),或者简单地循环位置参数。 嗯,按照该标准,没有任何外部命令可以安全使用。内置 getopts 缺少关键功能,如果您想检查 GETOPT_COMPATIBLE,这比移植 getopt 的功能更容易。 getoptutil-linux 包中,所以除非你试图同时支持许多不同的 *nix'es,否则你可能会没事,但这当然是件好事记住。【参考方案5】:

我知道这已经得到了回答,但是为了记录以及与我有相同要求的任何人,我决定发布这个相关的答案。代码中充斥着cmets来解释代码。

更新答案:

将文件另存为getopt.sh:

#!/bin/bash

function get_variable_name_for_option 
    local OPT_DESC=$1
    local OPTION=$2
    local VAR=$(echo $OPT_DESC | sed -e "s/.*\[\?-$OPTION \([A-Z_]\+\).*/\1/g" -e "s/.*\[\?-\($OPTION\).*/\1FLAG/g")

    if [[ "$VAR" == "$1" ]]; then
        echo ""
    else
        echo $VAR
    fi


function parse_options 
    local OPT_DESC=$1
    local INPUT=$(get_input_for_getopts "$OPT_DESC")

    shift
    while getopts $INPUT OPTION $@;
    do
        [ $OPTION == "?" ] && usage
        VARNAME=$(get_variable_name_for_option "$OPT_DESC" "$OPTION")
            [ "$VARNAME" != "" ] && eval "$VARNAME=$OPTARG:-true" # && printf "\t%s\n" "* Declaring $VARNAME=$!VARNAME -- OPTIONS='$OPTION'"
    done

    check_for_required "$OPT_DESC"



function check_for_required 
    local OPT_DESC=$1
    local REQUIRED=$(get_required "$OPT_DESC" | sed -e "s/\://g")
    while test -n "$REQUIRED"; do
        OPTION=$REQUIRED:0:1
        VARNAME=$(get_variable_name_for_option "$OPT_DESC" "$OPTION")
                [ -z "$!VARNAME" ] && printf "ERROR: %s\n" "Option -$OPTION must been set." && usage
        REQUIRED=$REQUIRED:1
    done


function get_input_for_getopts 
    local OPT_DESC=$1
    echo $OPT_DESC | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"


function get_optional 
    local OPT_DESC=$1
    echo $OPT_DESC | sed -e "s/[^[]*\(\[[^]]*\]\)[^[]*/\1/g" -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/[][ -]//g"


function get_required 
    local OPT_DESC=$1
    echo $OPT_DESC | sed -e "s/\([a-zA-Z]\) [A-Z_]\+/\1:/g" -e "s/\[[^[]*\]//g" -e "s/[][ -]//g"


function usage 
    printf "Usage:\n\t%s\n" "$0 $OPT_DESC"
    exit 10

那么你可以这样使用它:

#!/bin/bash
#
# [ and ] defines optional arguments
#

# location to getopts.sh file
source ./getopt.sh
USAGE="-u USER -d DATABASE -p PASS -s SID [ -a START_DATE_TIME ]"
parse_options "$USAGE" $@

echo $USER
echo $START_DATE_TIME

旧答案:

我最近需要使用通用方法。我遇到了这个解决方案:

#!/bin/bash
# Option Description:
# -------------------
#
# Option description is based on getopts bash builtin. The description adds a variable name feature to be used
# on future checks for required or optional values.
# The option description adds "=>VARIABLE_NAME" string. Variable name should be UPPERCASE. Valid characters
# are [A-Z_]*.
#
# A option description example:
#   OPT_DESC="a:=>A_VARIABLE|b:=>B_VARIABLE|c=>C_VARIABLE"
#
# -a option will require a value (the colon means that) and should be saved in variable A_VARIABLE.
# "|" is used to separate options description.
# -b option rule applies the same as -a.
# -c option doesn't require a value (the colon absense means that) and its existence should be set in C_VARIABLE
#
#   ~$ echo get_options $OPT_DESC
#   a:b:c
#   ~$
#


# Required options 
REQUIRED_DESC="a:=>REQ_A_VAR_VALUE|B:=>REQ_B_VAR_VALUE|c=>REQ_C_VAR_FLAG"

# Optional options (duh)
OPTIONAL_DESC="P:=>OPT_P_VAR_VALUE|r=>OPT_R_VAR_FLAG"

function usage 
    IFS="|"
    printf "%s" $0
    for i in $REQUIRED_DESC;
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
    printf " %s" "-$i:0:1 $VARNAME"
    done

    for i in $OPTIONAL_DESC;
    do
        VARNAME=$(echo $i | sed -e "s/.*=>//g")
        printf " %s" "[-$i:0:1 $VARNAME]"
    done
    printf "\n"
    unset IFS
    exit


# Auxiliary function that returns options characters to be passed
# into 'getopts' from a option description.
# Arguments:
#   $1: The options description (SEE TOP)
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   OPTIONS=$(get_options $OPT_DESC)
#   echo "$OPTIONS"
#
# Output:
#   "h:f:PW"
function get_options 
    echo $1 | sed -e "s/\([a-zA-Z]\:\?\)=>[A-Z_]*|\?/\1/g"


# Auxiliary function that returns all variable names separated by '|'
# Arguments:
#       $1: The options description (SEE TOP)
#
# Example:
#       OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#       VARNAMES=$(get_values $OPT_DESC)
#       echo "$VARNAMES"
#
# Output:
#       "H_VAR|F_VAR|P_VAR|W_VAR"
function get_variables 
    echo $1 | sed -e "s/[a-zA-Z]\:\?=>\([^|]*\)/\1/g"


# Auxiliary function that returns the variable name based on the
# option passed by.
# Arguments:
#   $1: The options description (SEE TOP)
#   $2: The option which the variable name wants to be retrieved
#
# Example:
#   OPT_DESC="h:=>H_VAR|f:=>F_VAR|P=>P_VAR|W=>W_VAR"
#   H_VAR=$(get_variable_name $OPT_DESC "h")
#   echo "$H_VAR"
#
# Output:
#   "H_VAR"
function get_variable_name 
    VAR=$(echo $1 | sed -e "s/.*$2\:\?=>\([^|]*\).*/\1/g")
    if [[ $VAR == $1 ]]; then
        echo ""
    else
        echo $VAR
    fi


# Gets the required options from the required description
REQUIRED=$(get_options $REQUIRED_DESC)

# Gets the optional options (duh) from the optional description
OPTIONAL=$(get_options $OPTIONAL_DESC)

# or... $(get_options "$OPTIONAL_DESC|$REQUIRED_DESC")

# The colon at starts instructs getopts to remain silent
while getopts ":$REQUIRED$OPTIONAL" OPTION
do
    [[ $OPTION == ":" ]] && usage
    VAR=$(get_variable_name "$REQUIRED_DESC|$OPTIONAL_DESC" $OPTION)
    [[ -n $VAR ]] && eval "$VAR=$OPTARG"
done

shift $(($OPTIND - 1))

# Checks for required options. Report an error and exits if
# required options are missing.

# Using function version ...
VARS=$(get_variables $REQUIRED_DESC)
IFS="|"
for VARNAME in $VARS;
do
    [[ -v $VARNAME ]] || usage
done
unset IFS

# ... or using IFS Version (no function)
OLDIFS=$IFS
IFS="|"
for i in $REQUIRED_DESC;
do
    VARNAME=$(echo $i | sed -e "s/.*=>//g")
    [[ -v $VARNAME ]] || usage
    printf "%s %s %s\n" "-$i:0:1" "$!VARNAME:=present" "$VARNAME"
done
IFS=$OLDIFS

我没有粗略地测试这个,所以我可能会有一些错误。

【讨论】:

如果您在函数中使用getopts,请将local OPTIND OPTARG 添加到函数中 @glennjackman 实际上它更像是一种 sed 方法,而不是使用 getopts 运行示例时,我得到./getopt.sh: line 38: : invalid variable name,它指向check_for_required() 的while 循环中的倒数第二行。 @pat-s 你能给你的例子贴个要点吗,也许我可以帮助你? @Sebastian 赞赏。我现在采用***.com/a/61055114/4185785 的方法,这似乎可行。我认为错误一定在我这边。感谢您分享您的解决方案!【参考方案6】:

POSIX 7 示例

还值得检查标准中的示例:http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html

aflag=
bflag=
while getopts ab: name
do
    case $name in
    a)    aflag=1;;
    b)    bflag=1
          bval="$OPTARG";;
    ?)   printf "Usage: %s: [-a] [-b value] args\n" $0
          exit 2;;
    esac
done
if [ ! -z "$aflag" ]; then
    printf "Option -a specified\n"
fi
if [ ! -z "$bflag" ]; then
    printf 'Option -b "%s" specified\n' "$bval"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: %s\n" "$*"

然后我们可以试一试:

$ sh a.sh
Remaining arguments are: 
$ sh a.sh -a
Option -a specified
Remaining arguments are: 
$ sh a.sh -b
No arg for -b option
Usage: a.sh: [-a] [-b value] args
$ sh a.sh -b myval
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh -a -b myval
Option -a specified
Option -b "myval" specified
Remaining arguments are: 
$ sh a.sh remain
Remaining arguments are: remain
$ sh a.sh -- -a remain
Remaining arguments are: -a remain

在 Ubuntu 17.10 中测试,sh 是破折号 0.5.8。

【讨论】:

【参考方案7】:

“getops”和“getopt”非常有限。虽然建议根本不要使用“getopt”,但它确实提供了很长的选项。其中“getopts”只允许单个字符选项,例如“-a”“-b”。使用其中任何一种都有一些缺点。

所以我编写了一个小脚本来替换“getopts”和“getopt”。 这是一个开始,它可能会改进很多。

2020 年 8 月 4 日更新:我添加了对连字符的支持,例如“ - 包裹名字”。

用法:"./script.sh package install --package "name with space" --build --archive"

# Example:
# parseArguments "$@"
# echo "$ARG_0" -> package
# echo "$ARG_1" -> install
# echo "$ARG_PACKAGE" -> "name with space"
# echo "$ARG_BUILD" -> 1 (true)
# echo "$ARG_ARCHIVE" -> 1 (true)
function parseArguments() 
  PREVIOUS_ITEM=''
  COUNT=0
  for CURRENT_ITEM in "$@"
  do
    if [[ $CURRENT_ITEM == "--"* ]]; then
      printf -v "ARG_$(formatArgument "$CURRENT_ITEM")" "%s" "1" # could set this to empty string and check with [ -z "$ARG_ITEM-x" ] if it's set, but empty.
    else
      if [[ $PREVIOUS_ITEM == "--"* ]]; then
        printf -v "ARG_$(formatArgument "$PREVIOUS_ITEM")" "%s" "$CURRENT_ITEM"
      else
        printf -v "ARG_$COUNT" "%s" "$CURRENT_ITEM"
      fi
    fi

    PREVIOUS_ITEM="$CURRENT_ITEM"
    (( COUNT++ ))
  done


# Format argument.
function formatArgument() 
  ARGUMENT="$1^^" # Capitalize.
  ARGUMENT="$ARGUMENT/--/" # Remove "--".
  ARGUMENT="$ARGUMENT//-/_" # Replace "-" with "_".
  echo "$ARGUMENT"

【讨论】:

这不能回答问题,但这是一些非常有趣的代码,它提供了解决问题的替代方法。感谢分享。

以上是关于如何在 bash 中使用 getopts 的示例的主要内容,如果未能解决你的问题,请参考以下文章

使用 getopts (bash) 的多个选项参数

如何在 Bash 中使用 getopt 和长选项?

在bash中使用getopts来获取可选的输入参数[重复]

如何在 bash 中结合 getopts 和位置参数? [复制]

在 Bash 中使用 getopts 检索单个选项的多个参数

在 bash 中使用 getopts 的布尔 cli 标志?