我想这样调用myscript文件:

$ ./myscript -s 45 -p any_string

or

$ ./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

但是使用这些代码,我会得到错误。怎么和巴斯一起去?


当前回答

使用getopt

为什么getopt ?

解析详细的命令行参数,以避免混淆,并澄清我们正在解析的选项,以便命令的读者能够理解发生了什么。

什么是getopt?

Getopt用于分解(解析)命令行中的选项,以方便shell过程进行解析,并检查合法选项。它使用GNU getopt(3)例程来做到这一点。

Getopt可以有以下类型的选项。

没有价值的选择 键值对选项

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

在语法/示例中,[]内的任何内容都是可选参数。 <value>是一个占位符,这意味着它应该被一个实际值取代。

如何使用getopt?

语法:First Form

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::'表示 Option -t有值,但是可选的。'::'表示可选。

在可选参数中,value不能与选项有空格分隔。因此,在“-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被分成五个部分之后

The command itself i.e. getopt The getopt_options, it describes how to parse the arguments. single dash long options, double dash options. The short options i.e. -o or --options. Just like the Form first syntax but with option "-o" and before the "--" (double dash). --, separates out the getopt_options from the options you want to parse and the allowed short options The parameters, these are the options that you have passed into the program. The options you want to parse and get the actual values set on them.

例子

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

GETOPT_OPTIONS

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

下面是一些getopt_选项

选项:-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

其他回答

使用getopt

为什么getopt ?

解析详细的命令行参数,以避免混淆,并澄清我们正在解析的选项,以便命令的读者能够理解发生了什么。

什么是getopt?

Getopt用于分解(解析)命令行中的选项,以方便shell过程进行解析,并检查合法选项。它使用GNU getopt(3)例程来做到这一点。

Getopt可以有以下类型的选项。

没有价值的选择 键值对选项

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

在语法/示例中,[]内的任何内容都是可选参数。 <value>是一个占位符,这意味着它应该被一个实际值取代。

如何使用getopt?

语法:First Form

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::'表示 Option -t有值,但是可选的。'::'表示可选。

在可选参数中,value不能与选项有空格分隔。因此,在“-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被分成五个部分之后

The command itself i.e. getopt The getopt_options, it describes how to parse the arguments. single dash long options, double dash options. The short options i.e. -o or --options. Just like the Form first syntax but with option "-o" and before the "--" (double dash). --, separates out the getopt_options from the options you want to parse and the allowed short options The parameters, these are the options that you have passed into the program. The options you want to parse and get the actual values set on them.

例子

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

GETOPT_OPTIONS

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

下面是一些getopt_选项

选项:-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

原始代码的问题是:

H:在不应该的地方期望参数,因此将其更改为H(不带冒号) 要使用-p any_string,需要将p:添加到参数列表中

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


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

getopts OPTSTRING VARNAME [ARGS...]

地点:

OPTSTRING is string with list of expected arguments, h - check for option -h without parameters; gives error on unsupported options; h: - check for option -h with parameter; gives errors on unsupported options; abc - check for options -a, -b, -c; gives errors on unsupported options; :abc - check for options -a, -b, -c; silences errors on unsupported options; Notes: In other words, colon in front of options allows you handle the errors in your code. Variable will contain ? in the case of unsupported option, : in the case of missing value. OPTARG - is set to current argument value, OPTERR - indicates if Bash should display error messages.

所以代码可以是:

#!/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

参见:Bash Hackers Wiki上的小getopts教程

在马克·G。的评论(在Adrian Frühwirth的答案下)变成了一个更可读的答案-这展示了如何避免使用getopts来获得可选参数:

usage() { 
    printf "Usage: %s <req> [<-s|--sopt> <45|90>] [<-p|--popt> <string>]\n" "$0"; 
    return 1; 
}; 

main() { 
    req="${1:?$(usage)}";
    shift; 
    s="";
    p="";
    while [ "$#" -ge 1 ]; do
        case "$1" in 
            -s|--sopt) 
                shift;
                s="${1:?$(usage)}";
                [ "$s" -eq 45 ] || [ "$s" -eq 90 ] || { 
                    usage; 
                    return 1; 
                } 
                ;; 
            -p|--popt) 
                shift; 
                p="${1:?$(usage)}" 
                ;; 
            *) 
                usage;
                return 1 
                ;; 
        esac; 
        shift;
    done; 
    printf "req = %s\ns = %s\np = %s\n" "$req" "$s" "$p"; 
};

main "$@"

正如n.caillou的评论所指出的:

如果选项和参数之间没有空格,它就会失败。

然而,为了使它更符合POSIX(来自Mark G。的其他评论):

        case "$1" in 
            -s*)
                s=${1#-s}; 
                if [ -z "$s" ]; 
                    shift; 
                    s=$1; 
                fi

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是dash 0.5.8。

#!/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