g e t o p t s可以编写脚本,使控制多个命令行参数更加容易。g e t o p t s用于形成命令行处理标
准形式。原则上讲,脚本应具有确认带有多个选项的命令文件标准格式的能力。
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。
• 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:
[sam@chenwy sam]$ ./getopt1 -a -h
ALL is true
HELP is true
[sam@chenwy sam]$ cat getopt1
#!/bin/sh
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。注意这里并没有用连字符指定每一单个选项。
运行上述脚本,给出几个有效和无效的选项,结果为:
[sam@chenwy sam]$ ./getopt1 -a -h
ALL is true
HELP is true
[sam@chenwy sam]$ ./getopt1 -a -h -p
ALL is true
HELP is true
./getopt1: illegal option -- p
[sam@chenwy sam]$ ./getopt1 -p
./getopt1: illegal option -- p
可以看出不同选项的结合方式。
2.2 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保存最后处理参数,一会儿就可以看出处理过程中这样做的好处。
2.3 使用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语句里使用?创建一可用语句捕获错误。
[sam@chenwy sam]$ cai getopt1
bash: cai: command not found
[sam@chenwy sam]$ cat getopt1
#!/bin/sh
ALL=false
HELP=false
FILE=false
VERBOSE=false
COPIES=0
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"
;;
?)
echo "`basename ` -[a h f v] -[c value] file"
;;
esac
done
输入所有合法选项:
[sam@chenwy sam]$ ./getopt1 -ah -c 3
ALL is true
HELP is true
COPIES is 3
选项- c不赋值,将返回错误,但显示的是脚本语句中的反馈信息
[sam@chenwy sam]$ ./getopt1 -ah -c
ALL is true
HELP is true
getopt1 -[a h f v] -[c value] file
去掉前面的冒号,提到系统的提示消息
:[sam@chenwy sam]$ ./getopt1 -ah -c
ALL is true
HELP is true
./getopt1: option requires an argument -- c
2.4 访问取值方式
g e t o p t s的一种功能是运行后台脚本。这样可以使用户加入选项,指定不同的磁带设备以备份数据。使用g e t o p t s实现此任务的基本框架如下:
[sam@chenwy sam]$ cat backups
#!/bin/sh
OUITE=n
DEVICE=awa
LOGFILE=/tmp/logbackup
usage()
{
echo "Usage: `basename ` -d [device] -l [logfile] -q"
exit 1
}
if [ $# = 0 ]
then
usage
fi
while getopts :qd:l: OPTION
do
case $OPTION in
q) QUIET=y
LOGFILE="/tmp/backup.log"
;;
d)DEVICE=$OPTION
;;
l)LOGFILE=$OPTARG
;;
?)usage
;;
esac
done
echo "you chlose the ..."
echo "Quite=$QUIET $DEVICE $LOGFILE"
上述脚本中如果指定选项d,则需为其赋值。该值为磁带设备路径。用户也可以指定是否备份输出到登录文件中的内容。运行上述脚本,指定下列输入:
[sam@chenwy sam]$ ./backups -d /dev/rmt0 -q
you chlose the ...
Quite=y d /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方法比较起来,会减少大量的编程工作。
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" ];
thenecho "doing upp 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版本相同。
脚本如下:
[sam@chenwy sam]$ cat tr_case1
#!/bin/sh
FILES=""
TRCASE=""
EXT=""
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 `: -[l|u] -v file[s]"
exit 1
;;
esac
done
shift `expr $OPTIND - 1`
if [ "$#" = "0" ] || [ "$OPT" = "no" ]
then
echo "usage: `basename `: -[l|u] -v file[s]"
exit 1
fi
for LOOP in "$@"
do
if [ ! -f $LOOP ]
then
echo "`basename ` :error cannot find file $LOOP"
exit 1
fi
echo $TRCASE $LOOP
case $TRCASE in
lower) if [ "VERBOSE" = "on" ];then
echo "doing...lower on $LOOP..newfile"
fi
cat $LOOP|tr "[a-z]" "[A-Z]" > $LOOP$EXT
;;
upper) if [ "VERBOSE" = "on" ];then
echo "doing upper on $LOOP..newfile"
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 显示方式或版本

3 小结
正确控制命令行选项会使脚本更加专业化,对于用户来说会使之看起来像一个系统命令。
本章讲到了控制命令行选项的两种方法, 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命令,脚本可以很容易偏移至所有调用参数,因此脚本可以做进一步处理。
 
 
-----------------------------------------------------------------------
获取UNIX类型的选项:
  unix有一个优点就是标准UNIX命令在执行时都具有相同的命令行格式:
  command -options parameters
  如果在执行Shell程序也采用上述格式,Bourne Shell中提供了一条获取和处理命令行选项的语句,即getopts语句。该语句的格式为:
  getopts option_string variable
  其中option_string中包含一个有效的单字符选项。若getopts命令在命令行中发现了连字符,那么它将用连字符后面的字符同option_string相比较。若有匹配,则把变量variable的值设为该选项。若无匹配,则variable设为?。当getopts发现连字符后面没有字符,会返回一个非零的状态值。Shell程序中可以利用getopts的返回值建立一个循环。
有时侯选项中还带一个值,getopts命令同样也支持这一功能。这时需要在option_string中选项字母后加一个冒号。当getopts命令发现冒号后,会从命令行该选项后读取该值。若该值存在,那么将被存在一个特殊的变量OPTARG中。如果该值不存在,getopts命令将在OPTARG中存放一个问号,并且在标准错误输出上显示一条消息。

optstring  option字符串,会逐个匹配
varname    每次匹配成功的选项
arg        参数列表,没写时它会取命令行参数列表
$OPTIND    特殊变量,option index,会逐个递增, 初始值为1
$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)

---------------
$ # 传递到脚本的参数个数
$ * 以一个单字符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可超过9个
$ $ 脚本运行的当前进程I D号
$ ! 后台运行的最后一个进程的进程I D号
$ @ 与$ #相同,但是使用时加引号,并在引号中返回每个参数
$ - 显示s h e l l使用的当前选项,与s e t命令功能相同
$ ? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
------------
shift 用于重新分配位置参数,其实就是把向参数左移动一个位置如:$1<--$2,$2<--$3老的$1将被删 除掉。
------------
范例:
[root@localhost ~]# cat getopts2
#!/bin/sh

while getopts :ab: name
do
    case $name in
       a)  aflag=1
           ;;
       b)  bflag=1
           bval=$OPTARG
           ;;
       \?) echo "USAGE:`basename $0` [-a] [-b value]"
           exit  1
           ;;
    esac
done
if [ ! -z $aflag ] ; then
          echo   "option -a specified"
          echo  "$aflag"
          echo "$OPTIND"
fi
if [ ! -z $bflag ] ; then
          echo   "option -b specified"
          echo  "$bflag"
          echo  "$bval"
          echo  "$OPTIND"
fi
echo "here  $OPTIND"
shift $(($OPTIND -1))
echo "$OPTIND"    
echo " `shift $(($OPTIND -1))`  "