Linux中SHELL内置getopts命令获取命令行参数

alt

做人如果没有梦想,那和咸鱼有何区别?

前言

写程序的时候经常要处理命令行参数,本文描述在Bash下的命令行处理方式。

选项与参数:

如下一个命令行:

1
/test.sh -f config.conf -v --prefix=/home

我们称-f为选项,它需要一个参数,即config.conf, -v 也是一个选项,但它不需要参数。

–prefix我们称之为一个长选项,即选项本身多于一个字符,它也需要一个参数,用等号连接,当然等号不是必须的,/home可以直接写在–prefix后面,即–prefix/home,更多的限制后面具体会讲到。

在bash中,可以用以下三种方式来处理命令行参数,每种方式都有自己的应用场景。

  • 手工处理方式
  • getopts
  • getopt

由于shell命令行的灵活性,自己编写代码判断时,复杂度会比较高。使用内部命令 getopts 可以很方便地处理命令行参数。一般格式为:

调用格式:

1
getopts options variable

getopts 的设计目标是在循环中运行,每次执行循环,getopts 就检查下一个命令行参数,并判断它是否合法。即检查参数是否以 - 开头,后面跟一个包含在 options 中的字母。如果是,就把匹配的选项字母存在指定的变量 variable 中,并返回退出状态0;如果 - 后面的字母没有包含在 options 中,就在 variable 中存入一个 ?,并返回退出状态0;如果命令行中已经没有参数,或者下一个参数不以 - 开头,就返回不为0的退出状态。

参数说明:

  • option_string 选项名称
  • variable 选项的值

选项之间使用冒号:分隔,也可以直接连接, : 表示选项后面有传值。
当getopts命令发现冒号后,会从命令行该选项后读取该值。如该值存在,将保存在特殊的变量OPTARG中。

当option_string用:开头,getopts会区分invalid option错误和miss option argument错误。

invalid option时, varname会被设成?

miss option argument时,varname会被设成:

如果option_string不用:开头,invalid option错误和miss option argument错误都会使varname被设成?。

getopts包含两个内置变量,OPTARG和OPTIND

  • OPTARG 保存选项后的参数值
  • OPTIND 表示命令行下一个选项或参数的索引

使用示例

例子1: 使用getopts命令获取参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash

while getopts a:b:c:d opts; do
case $opts in
a) a=$OPTARG ;;
b) b=$OPTARG ;;
c) c=$OPTARG ;;
d) d=$OPTARG ;;
?) ;;
esac
done

echo "a=$a"
echo "b=$b"
echo "c=$c"
echo "d=$d"

exit 0

执行输出

1
2
3
4
5
./test.sh -a 1 -b 2 -c 3 -d 4
a=1
b=2
c=3
d=

option_string a🅱c:d

a,b,c后都有:

d后没有:

所以可以获取到a,b,c的值

例子2: option_string前加:
上例中,如果a,b,c任意一个没有传值,将会提示出错。例如 -c 不传值。

1
2
3
4
5
6
./test.sh -a 1 -b 2 -c
./test.sh: option requires an argument -- c
a=1
b=2
c=
d=

我们在option_string前加上:,则可以屏蔽这个错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash

while getopts :a:b:c:d opts; do
case $opts in
a) a=$OPTARG ;;
b) b=$OPTARG ;;
c) c=$OPTARG ;;
d) d=$OPTARG ;;
?) ;;
esac
done

echo "a=$a"
echo "b=$b"
echo "c=$c"
echo "d=$d"

exit 0

执行输出

1
2
3
4
5
./test.sh -a 1 -b 2 -c
a=1
b=2
c=
d=

在option_string前加上:,可以屏蔽缺失传值的错误,但如果缺失的是前面选项的值,那么获取到的值将会错误。

例如缺失a的传值,命令会把-a后的-b作为了-a的值,导致错误。

1
2
3
4
5
./test.sh -a -b 2 -c 3
a=-b
b=
c=
d=

因此使用getopts命令时,对于没有传值的选项,选项名称也不要加入命令行中。
例如a不传值,则-a不要加入命令行。

1
2
3
4
5
./test.sh -b 2 -c 3
a=
b=2
c=3
d=

SHELL 代码

以上是示例,下面贴上我写的脚本代码:

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
#!/bin/bash
#
# Author: Created by jiemin.wang
# QQ: 278667010
# E-mail: 278661010@qq.com or wangjiemin880228@gmail.com
# Created Time: Wed Apr 3 14:15:12 CST 2019
# function: This is tcpdump grabs SQL executed by MySQL
# version: 1.0

function usage(){
echo "Usage:"
echo " $(basename $0) [OPTION]:"
echo " -n net"
echo " -P port"
}

if [ $# -eq "0" ];then
usage
exit 1
fi


while getopts :n:P: arg
do
case $arg in
n)
net=$OPTARG
;;
P)
port=$OPTARG
;;
esac
done

#tcpdump -i "$net" -s 0 -l -w - dst port "$port" | strings | perl -e '
tcpdump -i "$net" -s 0 -l -w file dst port "$port" | strings | perl -e '
#!/bin/bash
while(<>) { chomp; next if /^[^ ]+[ ]*$/;
if(/^(SELECT|UPDATE|DELETE|INSERT|SET|COMMIT|ROLLBACK|CREATE|DROP|ALTER|CALL)/i) {
if (defined $q) { print "$q\n"; }
$q=$_;
} else {
$_ =~ s/^[ \t]+//; $q.=" $_";
}
}'

其他示例

在网上找了一个示例,贴上来,仅供参考

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
#!/bin/bash 
QUIET=
VERBOSE=
DEVICE=
LOGFILE=/tmp/default

usage()
{
echo "Usage: `basename $0` [-qv] [-l LOGFILE] -d DEVICE input_file [input_file2...]"
exit 1
}

[ $# -eq 0 ] && usage

#option_string以冒号开头表示屏蔽脚本的系统提示错误,自己处理错误提示。
#后面接合法的单字母选项,选项后若有冒号,则表示该选项必须接具体的参数
while getopts :qvd:l: OPTION
do
case $OPTION in
q)
QUIET=y
;;
v)
VERBOSE=y
;;
d)
DEVICE=$OPTARG #$OPTARG为特殊变量,表示选项的具体参数
;;
l)
LOGFILE=$OPTARG
;;
\?) #如果出现错误,则解析为?
usage
;;
esac
done

#$OPTIND为特殊变量,表示第几个选项,初始值为1
shift $(($OPTIND - 1)) #除了选项之外,该脚本必须接至少一个参数
if [ $# -eq 0 ]; then
usage
fi

if [ -z "$DEVICE" ]; then #该脚本必须提供-d选项
echo "You must specify DEVICE with -d option"
exit
fi


echo "you chose the following options.."
echo "Quiet=$QUIET VERBOSE=$VERBOSE DEVICE=$DEVICE LOGFILE=$LOGFILE"

for file in $@ #依次处理剩余的参数
do
echo "Processing $file"
done

-------------本文结束感谢您的阅读-------------

本文标题:Linux中SHELL内置getopts命令获取命令行参数

文章作者:Wang Jiemin

发布时间:2019年04月03日 - 15:04

最后更新:2019年04月03日 - 15:04

原始链接:https://jiemin.wang/2019/04/03/shell-getopts/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

0%