shell 脚本里更好命令行参数
Table of Contents
我们经常需要在脚本中获取命令行参数,而 getopts 就是实现解析命令行参数的可靠工具,但也有它的局限性。
1 getopts
在频繁使用的小脚本中,getopts 可以说是完美的选择,它可以让你写更少的代码:
paste=vpaste # default is vertical pasting seplist="\t" # default separator is tab while getopts d:s o do case "$o" in d) seplist="$OPTARG";; s) paste=hpaste;; [?]) print >&2 "Usage: $0 [-s] [-d seplist] file ..." exit 1;; esac done shift $OPTIND-1 # perform actual paste command $paste -d "$seplist" "$@"
上述程序接受两个可选参数,-d xxx 和 -s,程序中把 xxx
保存在变量 seplist
中;如果指定了 -s
选项,则变量 paste=hpaste,
(默认是 vpasste)。
这么做虽然简单,但很快,你会忘记 -abc 到底是什么意思,而你的同事也会反复问你 -d 后面应该填什么。而且在功能复杂的脚本中,26个字母很快就会用完。这时候就需要自己解析命令行参数了。
2 目标
我们希望脚本可以接受类似 \(--var-a=xxx\) 和 \(--enable-feature-c\) 的参数。一般的,需要设置一个 \(--help\) 参数,如果被指定则打印每个参数的用途。
这只是一个脚本程序,我们希望它尽量简单明了,不需要太多的抽象。对脚本文件而言,“一把梭”可能是就是最好的。你的同事已经在主要功能上花费了太多的精力,当他以为已经完成了所有工作的时候,你告诉他有一个辅助脚本需要添加一个参数,为了添加这个参数需要理解其中复杂的逻辑,那就太令人绝望了。所以脚本应该让人看一眼就知道怎么修改,并且没有任何低估。因为是“一把梭”,我认为中间过程是没有必要的,所以代码就像这样:
3 示例代码
# 设置一些变量的默认值 # 这些变量用于保存命令行参数的解析结果 help=no VAR_A= VAR_B= HAVE_FEATURE_C=NO # for 循环遍历命令行参数,参数使用空格隔开 for option do # 获得参数的值,保存到变量 $value 中 case "$option" in -*=*) value=`echo "$option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;; *) value="" ;; esac # 枚举接受的命令行参数,逐一处理,根据参数对最开始的变量赋值 case "$option" in --help) help=yes ;; --var-a=*) VAR_A="$value" ;; --var-b=*) VAR_B="$value" ;; --have-feature-c) HAVE_FEATURE_C=YES ;; # ... *) echo "$0: error: invalid option \"$option\"" exit 1 ;; esac done # 打印帮助信息 if [ $help = yes ]; then cat << END --help print this message --var-a=ARG set var-a ... --var-b=ARG est var-b ... --have-feature-c enaable feature C ... END exit 1 fi # 如果参数为空,设置一些默认值,这是可选的 VAR_A=${VAR_A:-default_value1} # ... # 现在可以使用这些表示命令行参数的变量了 echo "VAR_A=$VAR_A; VAR_B=$VAR_B; HAVE_FEATURE_C=$HAVE_FEATURE_C" # ...