Posts 用getopts处理全部的选项和参数
Post
Cancel

用getopts处理全部的选项和参数

用getopts可以编写出像模像样的很规范的获取命令行参数/选项的参数。根据它的使用方法,命令参数列表存放在 optstring 中,变量名为name,后续还可以跟上参数。

1
getopts: usage: getopts optstring name [arg]

命令行的选项还分两种

  • 带值的选项
  • 不带值得选项(其实就是flag开关)

所以获取命令行需要处理三种数据

  • 带值的选项
  • 不带值得选项
  • 参数列表

比如构造一段opt.sh,带值的选项有 -a -b -c, flag选项有 -x -y -z ,参数列表为 hello和world

执行opt.sh可能的情形为:

1
opt.sh -a 1 -b 2 -c 3 -xyz hello.txt world.txt

因为选项 a,b,c带值,所以需要用冒号构造 a:b:c: , x,y,z不需要带值,直接构造列表 xyz ,getopts通过while循环读取每一个选项,保存在opt(也就是变量name)中。

1
2
3
4
5
6
7
8
9
10
11
while getopts a:b:c:xyz opt
do
  case "$opt" in 
    a) a_value=$OPTARG ;;
	b) b_value=$OPTARG ;;
	c) c_value=$OPTARG ;;
	x) x_flag="true" ;;
	y) y_flag="true" ;;
	z) z_flag="true" ;;
  esac
done

当opt为a,b或c的时,使用 OPTARG环境变量获取这个选项之后的值。选项和选项值可能的输入为:-a 1 或者 -a1 ,另外,-x -y -z 可以写成 -xyz, 这在各种bash命令中都是通用的。

处理完选项,需要处理[arg]列表。环境变量$OPTIND保存了参数列表所在的位置,所以我可以用shift快速地移掉前面所有的选项,只剩下参数列表,参数列表可以很容易通过$@获取。

1
2
3
4
5
6
shift $[ $OPTIND - 1 ]	

for p in $@
do
  echo "$p"
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
#!/bin/bash

while getopts a:b:c:xyz opt
do
  case "$opt" in 
    a) a_value=$OPTARG ;;
	b) b_value=$OPTARG ;;
	c) c_value=$OPTARG ;;
	x) x_flag="true" ;;
	y) y_flag="true" ;;
	z) z_flag="true" ;;
  esac
done

echo "a_value=$a_value"
echo "b_value=$b_value"
echo "c_value=$c_value"
echo "x_flag=$x_flag"
echo "y_flag=$y_flag"
echo "z_flag=$z_flag"


shift $[ $OPTIND - 1 ]

for p in $@
do
  echo "$p"
done

运行结果

1
2
3
4
5
6
7
8
9
$ opt.sh -a 1 -b 2 -c 3  -xyz hello.txt world.txt
a_value=1
b_value=2
c_value=3
x_flag=true
y_flag=true
z_flag=true
hello.txt
world.txt

小细节

如果输入了不存在的选项列表,或者带值选项没有提供一个值,这段脚本会提示错误

1
2
3
4
$ opt.sh -a 1 -b 2 -d -c

./opt.sh: illegal option -- d
./opt.sh: option requires an argument -- c

隐藏这个错误提示,可以在选项列表前多加一个冒号,比如:

1
while getopts :a:b:c:xyz opt
This post is licensed under CC BY 4.0 by the author.

权限转换的Shell脚本

用$*和$@读取全部参数的细节测试