如何在bash中将选项与参数分开?

如何在bash中将选项与参数分开?,bash,shell,Bash,Shell,我的脚本需要两个参数才能运行 如果需要,它可以有选项,所以我想确保这些属性,所以我编写了以下脚本 if [ $# -lt 3 ] then echo "This command need 3 arguments" else echo $1 $2 $3 fi 观察到“$#”统计传递的参数总数,包括选项 OUTPUT : sh my_script.sh -o optional1 -r. 它可以工作,但不像我的支票失败时所预期的那样 Expected Ou

我的脚本需要两个参数才能运行

如果需要,它可以有选项,所以我想确保这些属性,所以我编写了以下脚本

 if [ $# -lt 3 ]
    then
     echo "This command need 3 arguments"
    else
     echo $1 $2 $3
  fi
观察到“$#”统计传递的参数总数,包括选项

OUTPUT :
sh my_script.sh -o optional1 -r.
它可以工作,但不像我的支票失败时所预期的那样

Expected Output :(two arguments are compulsory)
sh my_script.sh arg1 arg2 --> should work
sh my_script.sh -o optional1 -r optional2 --> throw error that it requires two arguments
sh my_script.sh -o optional1 -r optional2 arg1 arg2 --> should work
  • 使用
    getopts
    处理选项

    r_flag=0
    o_flag="default value"
    while getopts o:r arg
    do
        case "$arg" in
        (o) o_flag="$OPTARG";;
        (r) r_flag=1;;
        (*) echo "Unrecognized option $arg" >&2; exit 1;;
        esac
    done
    
  • 循环完成后,使用
    shift$($OPTIND-1))
    删除已处理的选项

  • 现在,您可以检查是否还有至少两个参数:

    if [ $# -lt 2 ]
    then
        echo "Usage: $(basename $0 .sh) [-o option][-r] arg1 arg2 ..." >&2
        exit 1
    fi
    
  • 使用
    getopts
    处理选项

    r_flag=0
    o_flag="default value"
    while getopts o:r arg
    do
        case "$arg" in
        (o) o_flag="$OPTARG";;
        (r) r_flag=1;;
        (*) echo "Unrecognized option $arg" >&2; exit 1;;
        esac
    done
    
  • 循环完成后,使用
    shift$($OPTIND-1))
    删除已处理的选项

  • 现在,您可以检查是否还有至少两个参数:

    if [ $# -lt 2 ]
    then
        echo "Usage: $(basename $0 .sh) [-o option][-r] arg1 arg2 ..." >&2
        exit 1
    fi
    

  • 注意
    $#
    报告了参数数
    位置参数
    )。它不在乎它们是什么。命令行中的任何内容都被视为参数。(例如
    somevar
    -o
    )。因此,为了区分
    -foo
    foo
    ,您需要编写一个解释器,或者使用他人提供的
    getopts
    (作为该解释器)

    虽然
    getopts
    很好,但我通常需要自己的解释器。要在
    sh
    中提供自定义解释器,通常需要使用
    while循环
    移位
    case
    语句来检查每个位置参数并做出相应的响应。与
    bash
    相比,字符串操作在
    sh
    中有一定的局限性,这就足够了

    符合您需求的示例可以是:

    #!/bin/sh
    
    if [ $# -lt 2 ]; then
        printf "This command need 2 arguments\n"
        exit 1
    fi
    
    let nargs=0
    
    while [ "$1" != "" ]; do
        printf " processing: %s\n" "$1"
        case "$1" in
            -r  )   shift
                    [ "$1" = "" -o  `expr index "$1" "-"` -eq 1 ] && \
                    { printf "error: -r requires an option.\n"; exit 1; }
                    r_var="$1"
                    printf "   -r %s\n" "$r_var"
                    let nargs=$nargs+1
                    ;;
            -*  )   ;;  ## don't count '-x' arguments as options (change as needed)
            *   )   let nargs=$nargs+1
                    ;;
        esac
        shift
    done
    
    if [ $nargs -lt 2 ]; then
        printf "\n Two compulsory arguments not given.\n\n"
        exit 1
    else
        printf "\n required arguments satisfied.\n\n"
    fi
    
    
    exit 0
    
    示例使用/输出

    $ sh params.sh arg1 arg2
     processing: arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o optional -r
     processing: -o
     processing: optional
     processing: -r
    error: -r requires an option.
    
    
    $ sh params.sh -o optional -r arg1 arg2
     processing: -o
     processing: optional
     processing: -r
       -r arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o arg2
     processing: -o
     processing: arg2
    
     Two compulsory arguments not given.
    
    $ sh pdupes.sh a b c d e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b e
    i: c  j: 4 compare c d
    i: c  j: 5 compare c e
    i: d  j: 5 compare d e
    
    $ sh pdupes.sh a b c d b e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a b
    i: a  j: 6 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b b
    error: duplicate args [ b = b ], exiting.
    

    检查重复参数

    $ sh params.sh -o foo -r arg1 arg2 -o bar
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    error: multiple attempts to set '-o'. (foo, now 'bar')
    
    $ sh params.sh -o foo -r arg1 arg2 -o
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    
     required arguments satisfied.
    
    如果您不想尝试覆盖
    case
    语句中的所有内容,那么嵌套的
    for
    循环检查位置参数是否重复可能是检查重复参数的最佳方法。一种方法是在脚本开始时检查:

    #!/bin/sh
    
    let args=2
    
    ## check duplicate arguments
    for i ; do
        for j in $(seq $args $#); do
            printf "i: %s  j: %s compare %s %s\n" $i $j $i ${!j}  ## delete - just for info
            if [ $i = ${!j} ]; then
                printf "error: duplicate args [ %s = %s ], exiting.\n" $i ${!j}
                exit 1;
            fi
        done
        let args=$args+1
    done
    
    exit 0
    
    示例/输出

    $ sh params.sh arg1 arg2
     processing: arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o optional -r
     processing: -o
     processing: optional
     processing: -r
    error: -r requires an option.
    
    
    $ sh params.sh -o optional -r arg1 arg2
     processing: -o
     processing: optional
     processing: -r
       -r arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o arg2
     processing: -o
     processing: arg2
    
     Two compulsory arguments not given.
    
    $ sh pdupes.sh a b c d e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b e
    i: c  j: 4 compare c d
    i: c  j: 5 compare c e
    i: d  j: 5 compare d e
    
    $ sh pdupes.sh a b c d b e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a b
    i: a  j: 6 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b b
    error: duplicate args [ b = b ], exiting.
    

    防止两次接受论点

    除了上面的循环检查(将捕获任何重复项)之外,您还可以向
    case
    语句添加一个选项,以防止两次接受参数。这取决于您是否只想跳过重复或标记它并退出。在使用可选参数的
    -o
    的情况下,我会尝试下面的方法,它接受可选参数,测试它不是另一个
    -x
    类型,并检查它是否已经设置。如果它通过了所有测试,`o_var被设置,并且通过设置,它不能再次被设置:

        -o  )   shift
                [ "$1" = "" -o  `expr index "$1" "-"` -eq 1 -o ! -z $o_var ] && \
                { printf "duplicate value for '-o' received, exiting\n"; exit 1; } || \
                o_var="$1" && let nargs=$nargs+1
                printf "   -o %s\n" "$o_var"
                ;;
    
    控制重复响应的轻微变化

    有两种额外的方法可以处理多次尝试设置
    -o
    。第一种方法是在参数列表中第二次出现
    -o
    时退出(无论是否尝试设置与
    -o
    关联的可选变量):

    示例

    $ sh params.sh -o foo -r arg1 arg2 -o bar
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    error: multiple attempts to set '-o'. (foo, now 'bar')
    
    $ sh params.sh -o foo -r arg1 arg2 -o
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    
     required arguments satisfied.
    
    第二次设置
    -o
    的两次尝试被视为相同:

    $ sh params.sh -o foo -r arg1 arg2 -o bar
    $ sh params.sh -o foo -r arg1 arg2 -o
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    error: multiple attempts to set '-o', exiting.
    
    另一种可能性是,只有在第二次尝试设置与
    -o
    关联的可选变量时,才会抛出错误。(例如,如果第二个
    -o
    是无害的,则忽略它):

    示例

    $ sh params.sh -o foo -r arg1 arg2 -o bar
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    error: multiple attempts to set '-o'. (foo, now 'bar')
    
    $ sh params.sh -o foo -r arg1 arg2 -o
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    
     required arguments satisfied.
    

    注意
    $#
    报告了参数数
    位置参数
    )。它不在乎它们是什么。命令行中的任何内容都被视为参数。(例如
    somevar
    -o
    )。因此,为了区分
    -foo
    foo
    ,您需要编写一个解释器,或者使用他人提供的
    getopts
    (作为该解释器)

    虽然
    getopts
    很好,但我通常需要自己的解释器。要在
    sh
    中提供自定义解释器,通常需要使用
    while循环
    移位
    case
    语句来检查每个位置参数并做出相应的响应。与
    bash
    相比,字符串操作在
    sh
    中有一定的局限性,这就足够了

    符合您需求的示例可以是:

    #!/bin/sh
    
    if [ $# -lt 2 ]; then
        printf "This command need 2 arguments\n"
        exit 1
    fi
    
    let nargs=0
    
    while [ "$1" != "" ]; do
        printf " processing: %s\n" "$1"
        case "$1" in
            -r  )   shift
                    [ "$1" = "" -o  `expr index "$1" "-"` -eq 1 ] && \
                    { printf "error: -r requires an option.\n"; exit 1; }
                    r_var="$1"
                    printf "   -r %s\n" "$r_var"
                    let nargs=$nargs+1
                    ;;
            -*  )   ;;  ## don't count '-x' arguments as options (change as needed)
            *   )   let nargs=$nargs+1
                    ;;
        esac
        shift
    done
    
    if [ $nargs -lt 2 ]; then
        printf "\n Two compulsory arguments not given.\n\n"
        exit 1
    else
        printf "\n required arguments satisfied.\n\n"
    fi
    
    
    exit 0
    
    示例使用/输出

    $ sh params.sh arg1 arg2
     processing: arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o optional -r
     processing: -o
     processing: optional
     processing: -r
    error: -r requires an option.
    
    
    $ sh params.sh -o optional -r arg1 arg2
     processing: -o
     processing: optional
     processing: -r
       -r arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o arg2
     processing: -o
     processing: arg2
    
     Two compulsory arguments not given.
    
    $ sh pdupes.sh a b c d e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b e
    i: c  j: 4 compare c d
    i: c  j: 5 compare c e
    i: d  j: 5 compare d e
    
    $ sh pdupes.sh a b c d b e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a b
    i: a  j: 6 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b b
    error: duplicate args [ b = b ], exiting.
    

    检查重复参数

    $ sh params.sh -o foo -r arg1 arg2 -o bar
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    error: multiple attempts to set '-o'. (foo, now 'bar')
    
    $ sh params.sh -o foo -r arg1 arg2 -o
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    
     required arguments satisfied.
    
    如果您不想尝试覆盖
    case
    语句中的所有内容,那么嵌套的
    for
    循环检查位置参数是否重复可能是检查重复参数的最佳方法。一种方法是在脚本开始时检查:

    #!/bin/sh
    
    let args=2
    
    ## check duplicate arguments
    for i ; do
        for j in $(seq $args $#); do
            printf "i: %s  j: %s compare %s %s\n" $i $j $i ${!j}  ## delete - just for info
            if [ $i = ${!j} ]; then
                printf "error: duplicate args [ %s = %s ], exiting.\n" $i ${!j}
                exit 1;
            fi
        done
        let args=$args+1
    done
    
    exit 0
    
    示例/输出

    $ sh params.sh arg1 arg2
     processing: arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o optional -r
     processing: -o
     processing: optional
     processing: -r
    error: -r requires an option.
    
    
    $ sh params.sh -o optional -r arg1 arg2
     processing: -o
     processing: optional
     processing: -r
       -r arg1
     processing: arg2
    
     required arguments satisfied.
    
    
    $ sh params.sh -o arg2
     processing: -o
     processing: arg2
    
     Two compulsory arguments not given.
    
    $ sh pdupes.sh a b c d e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b e
    i: c  j: 4 compare c d
    i: c  j: 5 compare c e
    i: d  j: 5 compare d e
    
    $ sh pdupes.sh a b c d b e
    i: a  j: 2 compare a b
    i: a  j: 3 compare a c
    i: a  j: 4 compare a d
    i: a  j: 5 compare a b
    i: a  j: 6 compare a e
    i: b  j: 3 compare b c
    i: b  j: 4 compare b d
    i: b  j: 5 compare b b
    error: duplicate args [ b = b ], exiting.
    

    防止两次接受论点

    除了上面的循环检查(将捕获任何重复项)之外,您还可以向
    case
    语句添加一个选项,以防止两次接受参数。这取决于您是否只想跳过重复或标记它并退出。在使用可选参数的
    -o
    的情况下,我会尝试下面的方法,它接受可选参数,测试它不是另一个
    -x
    类型,并检查它是否已经设置。如果它通过了所有测试,`o_var被设置,并且通过设置,它不能再次被设置:

        -o  )   shift
                [ "$1" = "" -o  `expr index "$1" "-"` -eq 1 -o ! -z $o_var ] && \
                { printf "duplicate value for '-o' received, exiting\n"; exit 1; } || \
                o_var="$1" && let nargs=$nargs+1
                printf "   -o %s\n" "$o_var"
                ;;
    
    控制重复响应的轻微变化

    有两种额外的方法可以处理多次尝试设置
    -o
    。第一种方法是在参数列表中第二次出现
    -o
    时退出(无论是否尝试设置与
    -o
    关联的可选变量):

    示例

    $ sh params.sh -o foo -r arg1 arg2 -o bar
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    error: multiple attempts to set '-o'. (foo, now 'bar')
    
    $ sh params.sh -o foo -r arg1 arg2 -o
     processing: -o
       -o foo
     processing: -r
       -r arg1
     processing: arg2
     processing: -o
    
     required arguments satisfied.
    
    两次尝试都设置了