getopt——bash如何轻松传参

590 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

在编写bash脚本的时候,通过选项传入参数往往可以令我们使用脚本显得更加轻松、简明。下面就介绍一下利用getopt、shift以及case语句解决bash脚本传参的问题。

一、getopt函数

        getopt命令是一个在处理命令行选项和参数时非常方便的工具。它能够识别命令行参数,从而在脚本中解析它时更方便。

1.命令的格式

        getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格。它的命令格式:

        getopt optstring parameters

        opstring是这个过程的关键所在。它定义了命令行有效的选项字母,还定义了哪些选项字母需要参数值。

2.下面是最常用的getopt解析方式。

getopt -o SHORT_OPTIONS -l LONG_OPTIONS   -n  "0"  "0"  --  "@"

其中:

-o:SHORT_OPTIONS

--options SHORT_OPTIONS

        getopt通过"-o"选项收集命令行传递的短选项和它们对应的参数。

-l  LOGN_OPTIONS

--longoptions  LONG_OPTIONS

        getopt通过-l选项收集命令行传递的长选项和它们对应的参数。可能从的脚本中经常看到--long,是等价的,这个是长选项,长选项只要不产生歧义,是可以进行缩写的。

-n NAME

        getopt在解析命令行时,如果解析出错,getopt将使用该NAME作为报错的脚本名称。

--"$@"

        其中 -- 表示getopt命令自身的选项到此结束,后面的元素都是要被getopt解析的命令行参数。

3.getopt如何解析选项和参数。

        getopt使用"-o"或"-l"解析短、长选项和参数时,将会对每个解析到的选项、参数进行输出,然后不断放进一个字符串中。这个字符串的内容就是完整的、规范化的选项和参数。 

getopt使用"-o"选项解析短选项时:

        多个短选项可以连在一起

        如果某个要解析的选项需要一个参数,则在选项名后面跟一个冒号

        如果某个要解析的选项的参数可选,则在选项后面跟两个冒号

        例如,getopt -o ab:c::中,将解析为:-a -b arg_b -c [arg_c],arg_b是-b选项必须的,arg_c是-c选项可选的参数,"-a"选项无需参数

getopt使用"-l"选项解析长选项时(同短选项)

二、移动变量shift

        在使用shift命令时,默认情况下它会将每个参数变量向左移动一个位置。所以,变量3的值会移动到3的值会移动到2,变量2会移动到2会移动到1,而变量1则会被删除(注意:变量1则会被删除(注意:变量0,也就是程序名,不会改变)

#/bin/bash
while [ -n "$1" ]
do
    echo "Parameter #$count = $1"
    count=$[ count + 1 ]
    shift
done

bash test.sh 1 2 3 4 5

 1)查找选项:

通过case语句以及shift,我们可以实现选项的查找。

#/bin/bash
while [ -n "$1" ]
do
    case "$1" in
        -a) echo "Found the -a option";;
        -b) echo "Found the -b option";;
        -c) echo "Found the -c option";;
        *)  echo "$1 is not an option";;
    esac
    shift
done

        bash test.sh  -a -b -c

2)参数和选项

        遇到shell脚本中同时使用选项和脚本的情况。Linux中处理这个问题的标准方式是用特殊字符将二者分开,该字符会告诉脚本何时选项结束以及普通参数何时开始。

        对Linux来说,这个特殊字符就是双破折线(--)。shell会用双破折线来表明选项列表结束。在双破折线之后,脚本就可以放心地将剩下的命令行参数当作参数,而不是选项来处理了。要检查双破折线,只要在case中加上一项就行了。

#/bin/bash
while [ -n "$1" ]
do
    case "$1" in
        -a) echo "Found the -a option";;
        -b) echo "Found the -b option";;
        -c) echo "Found the -c option";;
        --) shift
            break;;
        *)  echo "$1 is not an option";;
    esac
    shift
done
count=1
for param in $@
do
    echo "Parameter #@count:$param"
    count=$[ $count + 1 ]
done

         bash test.sh  -a -b -c  --  1 2 3

3)运用getopt 

        bash的getopt命令经常用在shell脚本内部或函数内部,用来解析脚本执行或函数执行时传递的选项、参数。

         getopt解析选项时要做的许多事情之一是重新排列参数,以便非选项参数排在最后,并且组合的空头选项被拆分。

        这种效果反映在您的代码中,其中选项处理循环假定所有选项参数(包括选项的参数)首先出现,然后分别出现,最后是非选项参数。因此,TEMP包含重新排列、引用、拆分的选项,并使用eval set使它们成为脚本参数。

      至于shift,它会做它一直做的事情:删除第一个参数,并移动所有参数(因此2现在将是2现在将是1)。这消除了已处理的参数,因此,在此循环之后,只剩下非选项参数,您可以方便地使用$@而不必担心选项。

set -e 

ARGS=`getopt -o b:c:a:   -n '1.sh'  -- "$@" ` 
if [ $? != 0  ];then
    echo "Terminating..."
    exit 1
fi

#echo $ARGS
#gui fan hua ming ling hang can shu
eval set -- "${ARGS}"



while true
do
    case "$1" in
        -a)
            echo "Option a ,argument $2";
            shift   2
            ;;
        -b)
            echo "Option b,argument $2";
            b=$2
            shift 2
            ;;
        -c)
            case "$1" 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

        bash test.sh  -a 1   -b 2   -c 3