shell编程getopts

getopts 命令

用途

处理命令行参数,并校验有效选项。

语法

getopts 选项字符串 名称 [ 参数 ...]

描述

getopts 命令是 Korn/POSIX shell 的内置命令,用来从参数列表检索选项以及选项参数。选项由一个+(加号)或者是由一个-(减号)后跟一个字符开始。一个既不是以+,也不是以-开始的选项结束选项字符串。每次调用 getopts 命令时,它将下一个选项的值放置在名称内,并将下一个要处理的参数的索引置于 shell 变量 OPTIND 中。一旦调用了shell , OPTIND 将初始化为1。当选项以 +开头,则+ 将预先设为名称中的值。

如果选项字符串中的字符后面带有“:”(冒号),则预期此选项将带有参数。当选项需要选项参数时,getopts 命令就将其置于变量 OPTARG 中。

当查找到选项字符串所不包含的选项字符,或者查找到的选项没有所需的选项参数时:

  • 如果选项字符串不以:(冒号)开头,名称 将会被设置为 ?(问号)字符,OPTARG. 将被取消设置,并且诊断消息将被写入到标准错误中。

这种情况被认为是在将参数传递给所调用的应用程序的过程中所检测到的错误,而不是在处理 getopts 命令的过程中所发生的错误;如上所述,写入诊断消息,但退出状态将变为零。

  • 如果选项字符串以 :(冒号)开头,名称 将被设为 ? (问号)字符,这是对未知的选项来说的,或者为缺少的所需选项设为:(冒号)字符,OPTARG 将被设置为已查找到的选项字符,并且 标准错误中将不写入任何输出。

以下任何字符都可以识别选项结尾:特殊选项- -,查找到不以-,或者+为开头的参数,或者遇到错误。

当遇到选项结尾时:

  • getopts 命令将退出运行,并且返回值大于零,OPTARG 将被设置为第一个非选项参数索引,在这种情况下,如果第一个 - - 参数之前未出现其它非选项参数,将认为它是选项参数,或者如果没有非选项参数,设置为值 $#+1,名称将被设置为? (问号)字符,
参数

选项字符串
包含 getopts 命令识别的选项字符串。如果字符后带有冒号,则预期选项将带有参数,应该以单独参数的形式提供此参数。可以用空格将选项与参数分隔开。如果选项字符是未知的或者选项参数丢失,则选项字符串中的第一个字符将决定 getopts 命令的行为。

注意:应用程序不应该将问号和冒号字符作为选项字符。使用其它非字母数字的字符会产生不明的结果。

名称
由 getopts 命令对查找到的选项字符设置。

参数 ...
一个或多个被空格分隔的字符串,由 getopts 命令校验是否是合法选项。如果省略参数 ,就使用位置参数。有关位置参数的更多信息,请参见 Korn Shell 中的 参数替换

注意: 一般来说,不必将参数指定为 getopts 命令的一部分,但在进行脚本调试时可能会有所帮助。

退出状态

此命令返回下列出口值:

0
查找到由选项字符串指定的或未指定的选项。

<0
遇到选项结束或发生错误。

示例
  1. 下列 getopts 命令规定 ab 和 c 为有效选项,并且选项 a 和 c 带有参数:

    getopts a:bc: OPT
  2. 下列 getopts 命令指定 ab 以及 c 为有效选项, 并且选项 a 和 b 带有参数,而且 getopts 在命令行遇到为定义的选项时,它将 OPT 的值设置为 ?:

    getopts :a:b:c OPT
下列脚本分析和显示其参数:

 
aflag=
bflag=   
while getopts ab: name 
do             
<span style="white-space:pre">	</span>case $name in             
<span style="white-space:pre">		</span>a) aflag=1;;             
<span style="white-space:pre">		</span>b) bflag=1                           
<span style="white-space:pre">			</span>bval="$OPTARG";;             
<span style="white-space:pre">		</span>?) printf"Usage: %s: [-a] [-b value] args\n" $0                          
 <span style="white-space:pre">			</span>exit 2;;            
<span style="white-space:pre">	</span>esac 
done   
if [ ! -z "$aflag" ]; 
then            
<span style="white-space:pre">	</span>printf "Option -a specified\ n" 
fi   

if [ ! -z "$bflag" ]; 
then           
<span style="white-space:pre">	</span>printf'Option -b "%s" specified\ n' "$bval" 
fi  

shift $(($OPTIND -1)) 
printf "Remaining arguments are: %s\n" "$*"

在Bash里有以下用途:

optstring  option 字符串,会逐个匹配
varname    每次匹配成功的选项
arg        参数列表,没写时它会取命令行参数列表
$OPTIND    特殊变量,option index,会逐个递增
$OPTARG    特殊变量,option argument,不同情况下有不同的值

细则1:当optstring以”:“开头时,getopts会区分invalid option错误和miss option argument错误。
         invalid option时,varname会被设成?,$OPTARG是出问题的option;
         miss option argument时,varname会被设成:,$OPTARG是出问题的option。
        如果optstring不以”:“开头,invalid option错误和miss option argument错误都会使
        varname被设成?,$OPTARG是出问题的option。
细则2:当optstring中的字母跟”:“时,表明该option可接参数,参数(argument)放在$OPTARG中;
        如果缺参数,且optstring是以”:“开头,则varname的值会是:,$OPTARG是该option,
        否则varname的值是?,$OPTARG是该option。(参照细则1)

例子:gg.sh

[root@localhost shel]# cat gg.sh
#gg.sh
#!/bin/bash
while getopts  "abc:def:ghi" flag
do
  echo "$flag" $OPTIND $OPTARG         # 这里$OPTIND 是一个索引序列号,$OPTARG 是选项里所记录的值,无值是为空,默认情况下选项是以空格分隔
done
echo "Resetting"
OPTIND=1    while getopts  "abc:def:ghi" flag
do
  echo "$flag" $OPTIND $OPTARG
done

[root@localhost shel]# ./gg.sh -ab -c foo -f "foo bar" -h -gde
a 1  
b 2
c 4 foo
f 6 foo bar
h 7
g 7
d 7
e 8
Resetting
a 1
b 2
c 4 foo
f 6 foo bar
h 7
g 7
d 7
e 8

上面是显示结果。

如果调整一下所给参数的位置:

[root@localhost shel]# ./gg.sh -abc foo -f "foo bar" -h –gde  a 1
b 1
c 3 foo
f 5 foo bar
h 6
g 6
d 6
e 7
Resetting
a 1
b 1
c 3 foo
f 5 foo bar
h 6
g 6
d 6
e 7


g e t o p t s可以编写脚本,使控制多个命令行参数更加容易。g e t o p t s用于形成命令行处理标 
准形式。原则上讲,脚本应具有确认带有多个选项的命令文件标准格式的能力。 

20.2.1 getopts脚本实例 
通过例子可以更好地理解g e t o p t s。以下g e t o p t s脚本接受下列选项或参数。 
• a 设置变量A L L为t r u e。 
• h 设置变量H E L P为t r u e。 
第20章向脚本传递参数229 
下载 
• f 设置变量F I L E为t r u e。 
• v 设置变量V E R B O S E为t r u e。 
对于所有变量设置,一般总假定其初始状态为f a l s e: 
#!/bin/bash 
# getopt1.sh 
# set the vars 
ALL=false 
HELP=false 
FILE=false 
VERBOSE=false 
while getopts ahfgv OPTION 
do 
        case $OPTION in 
                a) ALL=true 
                echo "ALL is $ALL" 
                ;; 
                h) HELP=true 
                echo "HELP is $HELP" 
                ;; 
                f) FILE=true 
                echo "FILE is $FILE" 
                ;; 
                v) VERBOSE=true 
                echo "VERBOSE is $VERBOSE" 
                ;; 
        esac    
done   

g e t o p t s一般格式为: 
getopts option_string variable 
在上述例子中使用脚本: 
while getopts ahfgv OPTION 
可以看出w h i l e循环用于读取命令行,o p t i o n s t r i n g为指定的5个选项(- a,- h,- f,- g,- v), 
脚本中v a r i a b l e为O P T I O N。注意这里并没有用连字符指定每一单个选项。 
运行上述脚本,给出几个有效和无效的选项,结果为: 
[root@localhost ~]# sh getopt1.sh -a -h 
ALL is true 
HELP is true 
[root@localhost ~]# sh getopt1.sh -a -h -p 
ALL is true 
HELP is true 
getopt1.sh: illegal option -- p 
复制代码 
可以看出不同选项的结合方式。 

----------- 
getopts使用方式 

g e t o p t s读取o p t i o n s t r i n g,获知脚本中使用了有效选项。 
g e t o p t s查看所有以连字符开头的参数,将其视为选项,如果输入选项,将把这与 
o p t i o n s t r i n g对比,如果匹配发现,变量设置为O P T I O N,如果未发现匹配字符,变量能够设 
置为?。重复此处理过程直到选项输入完毕。 
g e t o p t s接收完所有参数后,返回非零状态,意即参数传递成功,变量O P T I O N保存最后处 
理参数,一会儿就可以看出处理过程中这样做的好处。 

--- 
使用getopts指定变量取值 

有时有必要在脚本中指定命令行选项取值。g e t o p t s 为此提供了一种方式,即在 
o p t i o n s t r i n g中将一个冒号放在选项后。例如: 
getopts ahfvc: OPTION 
上面一行脚本指出,选项a、h、f、v可以不加实际值进行传递,而选项c必须取值。使用 
选项取值时,必须使用变量O P TA R G保存该值。如果试图不取值传递此选项,会返回一个错 
误信息。错误信息提示并不明确,因此可以用自己的反馈信息屏蔽它,方法如下: 
将冒号放在o p t i o n s t r i n g开始部分。 
while getopts :ahfgvc: OPTION 
在c a s e语句里使用?创建一可用语句捕获错误。 
#!/bin/bash 
# getopt2.sh 
# set the vars 
ALL=false 
HELP=false 
FILE=false 
VERBOSE=false 
COPIES=0 
# the value for the -c option is set to zero 
while getopts ahfgvc: OPTION 
do 
        case $OPTION in 
                a) ALL=true 
                echo "ALL is $ALL" 
                ;; 
                h) HELP=true 
                echo "HELP is $HELP" 
                ;; 
                f) FILE=true 
                echo "FILE is $FILE" 
                ;; 
                v) VERBOSE=true 
                echo "VERBOSE is $VERBOSE" 
                ;; 
                c) COPIES=$OPTARG 
                echo "COPIES is $COPIES" 
                \?) # usage statement 
                echo "`basename $0` -[a h f v] -[c value] file" >&2 
                ;; 
        esac    
done 

运行上述脚本,选项- c不赋值,将返回错误,但显示的是脚本语句中的反馈信息: 
[root@localhost ~]# sh getopt2.sh -ah -c 
ALL is true 
HELP is true 
getopt2.sh: option requires an argument -- c 
getopt2.sh -[a h f v] -[c value] file 

现在输入所有的合法选项: 
[root@localhost ~]# sh getopt2.sh -ah -c 3 
ALL is true 
HELP is true 
COPIES is 3 

-- 
访问取值方式 

g e t o p t s的一种功能是运行后台脚本。这样可以使用户加入选项,指定不同的磁带设备以 
备份数据。使用g e t o p t s实现此任务的基本框架如下: 

#!/bin/bash 
# backups.sh 
QUITE=n 
DEVICE=awa 
LOGFILE=/tmp/logbackup 
usage() 

        echo "Usage: `basename $0` -d [device] -l [logfile] -q" 
        exit 1 

if [ $# == 0 ]; then 
        usage 
fi 
while getopts :qd:l: OPTION 
do 
        case $OPTION in 
                q) QUITE=y 
                LOGFILE="/tmp/backup.log" 
                ;; 
                d) DEVICE=$OPTARG 
                ;; 
                l) LOGFILE=$OPTARG 
                ;; 
                \?) usage 
                ;; 
        esac 
done 
echo "you chose the following options .. I can process these" 
echo "Quite= $QUITE $DEVICE $LOGFILE" 

上述脚本中如果指定选项d,则需为其赋值。该值为磁带设备路径。用户也可以指定是否 
备份输出到登录文件中的内容。运行上述脚本,指定下列输入: 

[root@localhost ~]# sh backups.sh -d/dev/rmt0 -q 
you chose the following options .. I can process these 
Quite= y /dev/rmt0 /tmp/backup.log 
g e t o p t s检查完之后,变量O P TA R G取值可用来进行任何正常的处理过程。当然,如果输 
入选项,怎样进行进一步处理及使该选项有有效值,完全取决于用户。 
以上是使用g e t o p t s对命令行参数处理的基本框架。 
实际处理文件时,使用f o r循环,就像在t r- c a s e脚本中使用s h i f t命令过滤所有选项一样。 
使用g e t o p t s与使用s h i f t方法比较起来,会减少大量的编程工作。 
------- 
使用getopts处理文件转换 

现在用所学知识将t r- c a s e脚本转换为g e t o p t s版本。命令行选项g e t o p t s方法与s h i f t方法的唯 
一区别是一个V E R B O S E选项。 
变量V E R B O S E缺省取值为n o,但选择了命令行选项后, c a s e语句将捕获它,并将其设为 
y e s,反馈的命令是一个简单的i f语句。 
if [ "$VERBOSE" == "on" ]; then 
                        echo "doing..lower on $LOOP .. newfile called $LOOP$EXT" 
                fi   

20.2.5 使用getopts处理文件转换 

现在用所学知识将t r- c a s e脚本转换为g e t o p t s版本。命令行选项g e t o p t s方法与s h i f t方法的唯 
一区别是一个V E R B O S E选项。 
变量V E R B O S E缺省取值为n o,但选择了命令行选项后, c a s e语句将捕获它,并将其设为 
y e s,反馈的命令是一个简单的i f语句。 
if [ "$VERBOSE" == "on" ]; then 
                        echo "doing..lower on $LOOP .. newfile called $LOOP$EXT" 
                fi   
复制代码 
如果正在使用其他系统命令包,它总是反馈用户动作,只需简单地将包含错误的输出重 
定向到/ d e v / n u l l中即可。如: 
命令>/dev/null 2 >&1 
缺省时V E R B O S E关闭(即不显示),使用- v选项可将其打开。例如要用V E R B O S E将 
m y f i l e文件系列转换为小写,方法如下: 
tr-case -l -v myfile1 myfile2 ... 
或者 
tr-case -v -l myfile1 myfile2 ... 
可能首先注意的是使用g e t o p t s后脚本的缩减效果。这里用于文件处理的脚本与s h i f t版本 
相同。 
脚本如下: 
#!/bin/bash 
# tr_case2.sh 
# convert case, using getopts 
EXT="" 
TRCASE="" 
FLAG="" 
OPT="no" 
VERBOSE="off" 
while getopts :luv OPTION 
do 
        case $OPTION in 
                l) TRCASE="lower" 
                EXT=".LC" 
                OPT=yes 
                ;; 
                u) TRCASE="upper" 
                EXT=".UC" 
                OPT=yes 
                ;; 
                v) VERBOSE=on 
                ;; 
                \?) echo "usage: `basename $0`: -[l|u] --v file[s]" 
                        echo "doing.. lower on $LOOP .. newfile called $LOOP$EXT 
                exit 1 
                ;; 
        esac    
done    
# next argument down only please 
shift `expr $OPTION - 1` 
# are there any argument passed ?? 
if [ "$#" == "0" ] || [ "$OPT" == "no" ]; then 
        echo "usage: `basename $0` : -[l|u] -v file[s]" >&2 
        exit 1 
fi      
for LOOP in "$@" 
do      
        if [ ! -f $LOOP ]; then 
                echo "`basename $0` : Error cannot find file $LOOP" >&2 
                exit 1 
        fi      
        echo $TRCASE $LOOP 
        case $TRCSSE in 
                lower) 
                if [ "$VERBOSE" == "on" ]; then 
                        echo "doing..lower on $LOOP .. newfile called $LOOP$EXT" 
                fi      
                cat $LOOP | tr "[a-z]" "[A-Z]" > $LOOP$EXT 
                ;; 
                upper) 
                if [ "$VERBOSE" == "on" ]; then 
                        echo "doing..lower on $LOOP ..newfile called $LOOP$EXT" 
                fi      
                cat $LOOP | tr "[A-Z]" "[a-z]" >$LOOP$EXT 
                ;; 
        esac    
done   

在脚本中指定命令行选项时,最好使其命名规则与U N I X或L I N U X一致。下面是一些选项 
及其含义的列表。 
选项含义 
- a 扩展 
- c 计数、拷贝 
- d 目录、设备 
- e 执行 
- f 文件名、强制 
- h 帮助 
- i 忽略状态 
- l 注册文件 
- o 完整输出 
- q 退出 
- p 路径 
-v 显示方式或版本 

正确控制命令行选项会使脚本更加专业化,对于用户来说会使之看起来像一个系统命令。 
本章讲到了控制命令行选项的两种方法, s h i f t和g e t o p t s。使用g e t o p t s检测脚本的数量远远小 
于使用s h i f t方法检测脚本的数量。 
s h i f t也克服了脚本参数$ 1 . . $ 9的限制。使用s h i f t命令,脚本可以很容易偏移至所有调用参 
数,因此脚本可以做进一步处理。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值