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

时间:2015-06-29 06:47:34

标签: 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 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

3 个答案:

答案 0 :(得分:2)

  1. 使用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
    
  2. 循环完成后,使用shift $(($OPTIND - 1))删除已处理的选项。

  3. 现在您可以检查至少还有2个参数:

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

答案 1 :(得分:2)

注意$#报告参数数量positional parameters)。它并不关心它们是什么。命令行上的任何内容都被视为参数。 (例如somevar-o)。因此,要区分-foofoo,您需要编写解释器,或者使用其他人提供的getopts(作为解释器)

虽然getopts没问题,但我通常需要自己的翻译。要在sh中提供自定义解释器,您通常会使用while loopshiftcase语句来检查每个位置参数并做出相应的响应。虽然与sh相比,bash中的字符串操作有限,但这已足够。

符合您要求的示例可能是:

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

检查重复参数

如果您不想尝试覆盖for语句中的所有内容,则检查重复项的位置参数的嵌套case循环可能是检查重复参数的最佳方法。一种方法是检查脚本的开头:

#!/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 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关联的可选变量):

    -o  )   shift
            ## throw error on any second instance of '-o' 
            if [ -z "$o_var" ]; then
                if [ ! `expr index "$1" "-"` -eq 1 -a "$1" != "" ]; then
                    o_var="$1"
                    let nargs=$nargs+1
                    printf "   -o %s\n" "$o_var"
                fi
            else
                    printf "error: multiple attempts to set '-o', exiting.\n" "$o_var" "$1"
                    exit 1                
            fi
            ;;

<强>实施例

第二次设置-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无害,请忽略它):

    -o  )   shift
            ## throw error only if second instance of '-o' has optional argument
            if [ "$1" != "" -a ! `expr index "$1" "-"` -eq 1 ]; then
                if [ -z "$o_var" ]; then
                    o_var="$1"
                    let nargs=$nargs+1
                    printf "   -o %s\n" "$o_var"
                else
                    printf "error: multiple attempts to set '-o'. (%s, now '%s')\n" "$o_var" "$1"
                    exit 1
                fi
            fi
            ;;

<强>实施例

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

答案 2 :(得分:2)

没有getopts,但几乎是同样的事情,我更喜欢这种方式,因为它更容易添加长args。

#!/bin/bash


while true;do

        case $1 in

        '-o'|'--optional')
                optional1=$2
                shift 2
                ;;
        '-r')
                optional2=$2
                shift 2
                ;;
        *)
                break
                ;;
        esac
done

if [[ $# -lt 2 ]];then
    echo Too few args.
    exit 1
fi

echo $optional1
echo $optional2

显然它可能更强大,因为这将采用多个相同的标志。