选项和参数:
- Argument, Option: 中文对应「选项」,形如 -a, –save 的都是选项;选项可以接收参数(Parameter),也可以不接受参数。其中-a 为短选项, –save 为长选项
- Flag: 中文对应「标签」,形如 -v(verbose);标签是布尔值,不接受参数。
bash shell 汇总有三种解析参数的方式:
- 手工处理: 大多数简单的命令
- getopts: 大多数复杂命令, 不支持长选项
- getopt: 支持长选项, getopts和getopt功能相似但又不完全相同,其中getopt是独立的可执行文件,而getopts是由Bash内置的
1
|
$ ./test.sh -v -f -out /test.log --prefix=/home
|
如果执行是permission denied: test.sh, 运行 chmod +x test.sh 赋予其可执行权限 或是 通过sh/bash 命令运行
手工处理
- $0 : 在用sh 或者 ./执行脚本时,指的是脚本名,用source或.执行时,永运是bash,这也反应了sh 或者 ./执行脚本的原理和source的方式是不同的.
- $1 : -v,第一个参数.
- $2 : -f
- $3 : -out
- $4 : /test.log
- 依次类推 $5 $6 …
- $# : 参数的个数,不包括命令本身,上例中$#为5.
- $@ : 参数本身的列表,也不包括命令本身,如上例为 -v -f -out /test.log –prefix=/home
- $* : 参数本身的列表,也不包括命令本身,但"$*" 和"$@"(加引号)并不同,"$*“将所有的参数解释成一个字符串,而”$@“是一个参数数组。如下例所示:
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/bash
for arg in "$*"
do
echo $arg
done
for arg in "$@"
do
echo $arg
done
|
1
2
3
4
5
6
|
-v -f -out /test.log --prefix=/home
-v
-f
-out
/test.log
--prefix=/home
|
也就是说手工处理方式高度依赖命令行中参数的位置, 只适合简单的参数较少的命令, 手工处理方式能满足大多数的简单需求,配合shift使用也能构造出强大的功能
getopts
先来看看参数传递的典型用法:
- ./test.sh -a -b -c : 短选项,各选项不需参数
- ./test.sh -abc : 短选项,和上一种方法的效果一样,只是将所有的选项写在一起。
- ./test.sh -a args -b -c :短选项,其中-a需要参数,而-b -c不需参数。
- ./test.sh –a-long=args –b-long :长选项
getopts 用法
变量
- OPTIND: getopts 在解析传入 Shell 脚本的参数时(也就是 $@),并不会执行 shift 操作,而是通过变量 OPTIND 来记住接下来要解析的参数的位置。
- OPTARG: getopts 在解析到选项的参数时,就会将参数保存在 OPTARG 变量当中;如果 getopts 遇到不合法的选项,择把选项本身保存在 OPTARG 当中。
1
|
getopts OPTSTRING VARNAME [ARGS...]
|
- OPTSTRING 记录合法的选项列表(以及参数情况)
- VARNAME 则传入一个 Shell 变量的名字,用于保存 getopts 解析到的选项的名字(而不是参数值,参数值保存在 OPTARG 里)
- ATGS… 是可选的,默认是 $@,即传入 Shell 脚本的全部参数
通常来说,我们会将 getopts 放在 while 循环的条件判断式中。getopts 在顺利解析到参数的时候,会返回 TRUE;否则返回 FALSE,用以结束循环.
1
2
3
|
while getopts ...; do
...
done
|
getopts 在两种情况下会停止解析并返回 FALSE:
- getopts 读入不以 - 开始的字符串;比如: sh test.sh flag
- getopts 读入连续的两个 - (i.e. –)
OPTSTRING
通过 OPTSTRING getopts 知道哪些参数是合法的,哪些参数又是需要接受参数的。
OPTSTRING 的格式很简单,就是一个简单的字符串。字符串里,每一个字母(大小写均可,但区分大小写)都是一个选项的名字。
值得一提的是冒号 (:)
在 OPTSTRING 中,冒号有两种含义:
- 首位的 : 表示「不打印错误信息」;
- 紧邻字母(选项名字)的 : 表示该选项接收一个参数。
例如:
1
2
|
getopts aBcD VARNAME // 该脚本接受四个标签-a, -B, -c, -D, 均不接受参数
getopts :aB:Cd VARNAME // 该脚本接受两个标签-a, -B, 两个短选项-C, -d
|
下面是实例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#!/bin/bash
echo "$@"
while getopts ":a:bc:" opt; do #不打印错误信息, -a -c需要参数 -b 不需要传参
case $opt in
a)
echo "-a arg:$OPTARG index:$OPTIND" #$OPTIND指的下一个选项的index
;;
b)
echo "-b arg:$OPTARG index:$OPTIND"
;;
c)
echo "-c arg:$OPTARG index:$OPTIND"
;;
:)
echo "Option -$OPTARG requires an argument."
exit 1
;;
?) #当有不认识的选项的时候arg为?
echo "Invalid option: -$OPTARG index:$OPTIND"
;;
esac
done
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
$ ./test.sh -a ssss -b ssss -c
>>
-a ssss -b ssss -c
-a arg:ssss index:3
-b arg: index:4 #-b并不接受参数, 解析到ssss时直接停止解析
$ ./test.sh -c xxx -b -a ssssss
>>
-c xxx -b -a ssssss
-c arg:xxx index:3
-b arg: index:4
-a arg:ssssss index:6
$ ./test.sh -c -b -a ssssss // -c 后面没有参数 -b会解析成-c参数
>>
-c -b -a ssssss
-c arg:-b
-a arg:ssssss
$ ./test.sh -a
>>
a
Option -a requires an argument.
|
getopt
getopt较bash内置的getopts更强大,其不仅支持短参-s,还支持–longopt的长参数,甚至支持-longopt的简化参数。相较于getopts ,getopts 不但支持长短选项,其还支持选项和参数放在一起写。
getopt 用法
1
|
getopt [options] -o|--options optstring [options] [--] parameters
|
选项说明:
-a:使getopt长参数支持”-“符号打头,必须与-l同时使用
-l:后面接getopt支持长参数列表
-n program:如果getopt处理参数返回错误,会指出是谁处理的这个错误,这个在调用多个脚本时,很有用
-o:后面接短参数列表,这种用法与getopts类似
-u:不给参数列表加引号,默认是加引号的(不使用-u选项),例如在加引号的时候 –longoption “arg1 arg2” ,只会取到"arg1”,而不是完整的"arg1 arg2"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#!/bin/bash
# A small example program for using the new getopt(1) program.
# This program will only work with bash(1)
# Note that we use `"$@"' to let each command-line parameter expand to a
# separate word. The quotes around `$@' are essential!
# We need TEMP as the `eval set --' would nuke the return value of getopt.
TEMP=`getopt -o ab:c:: --long a-long,b-long:,c-long:: -n 'example.bash' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
while true ; do
case "$1" in
-a|--a-long) echo "Option a" ; shift ;;
-b|--b-long) echo "Option b, argument \`$2'" ; shift 2 ;;
-c|--c-long)
# c has an optional argument. As we are in quoted mode,
# an empty parameter will be generated if its optional
# argument is not found.
case "$2" 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
echo "Remaining arguments:"
for arg do echo '--> '"\`$arg'" ; done
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
#!/bin/bash
ARGS=`getopt -a -o I:D:T:e:k:LMSsth -l instence:,database:,table:,excute:,key:,list,master,slave,status,tableview,help -- "$@"`
function usage() {
echo 'help'
}
[ $? -ne 0 ] && usage
#set -- "${ARGS}"
eval set -- "${ARGS}"
while true
do
case "$1" in
-I|--instence)
instence="$2"
shift
;;
-D|--database)
database="$2"
shift
;;
-T|--table)
table="$2"
shift
;;
-e|--excute)
excute="yes"
shift
;;
-k|--key)
key="$2"
shift
;;
-L|--list)
LIST="yes"
;;
-M|--master)
MASTER="yes"
;;
-S|--slave)
SLAVE="yes"
;;
-A|--alldb)
ALLDB="yes"
;;
-s|--status)
STATUS="yes"
;;
-t|--tableview)
TABLEVIEW="yes"
;;
-h|--help)
usage
;;
--)
shift
break
;;
esac
shift
done
echo instence:$instence database:$database table:$table excute:$excute key:$key
|
选项标准化
在创建shell脚本时,尽量保持选项与Linux通用的选项含义相同,Linux通用选项有:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
-a 显示所有对象
-c 生产一个计数
-d 指定一个目录
-e 扩展一个对象
-f 指定读入数据的文件
-h 显示命令的帮助信息
-i 忽略文本大小写
-l 产生输出得长格式文本
-n 使用非交互模式
-o 指定将所有输出重定向到输出文件
-q 以安静模式运行
-r 递归的处理目录和文件
-s 以安静模式运行
-v 生成详细输出
-x 排除某个对象
-y 对所有问题回答yes
|