使用getopt设计shell脚本选项示例
这里提供一个和seq命令功能相同的脚本seq.sh,然后设计这个脚本的选项。
先看一下seq命令的各个选项说明:
seq [OPTION]... LAST # 语法1
seq [OPTION]... FIRST LAST # 语法2
seq [OPTION]... FIRST INCREMENT LAST # 语法3
选项:
-s, --separator=STRING
使用指定的STRING分隔各数值,默认值为"\n"u
-w, --equal-width
使用0填充在前缀使所有数值长度相同
--help
显示帮助信息并退出
--version
输出版本信息并退出
以下是脚本内容:和seq相比,只有两个问题:第一个起点数值FIRST不能为负数;不支持小数功能。其它功能完全相同
#!/usr/bin/env bash
usage(){
cat <<'EOF'
Usage: $0 [OPTION]... LAST
or: $0 [OPTION]... FIRST LAST
or: $0 [OPTION]... FIRST INCREMENT LAST
EOF
}
# getopt的版本是增强版吗
getopt -T &>/dev/null;[ $? -ne 4 ] && { echo "not enhanced version";exit 1; }
# 参数解析
parameters=`getopt -o +s:w --long separator:,equal-width,help,version -n "$0" -- "$@"`
[ $? -ne 0 ] && { echo "Try '$0 --help' for more information."; exit 1; }
eval set -- "$parameters"
while true;do
case "$1" in
-w|--equal-width) ZERO_PAD="true"; shift ;;
-s|--separator) SEPARATOR=$2; shift 2 ;;
--version) echo "$0 version V1.0"; exit ;;
--help) usage;exit ;;
--)
shift
FIRST=$1
INCREMENT=$2
LAST=$3
break ;;
*) usage;exit 1;;
esac
done
# 用于生成序列数
function seq_func(){
# 是否要使用printf填充0位?
[ "x$1" = "xtrue" ] && zero_pad="true" && shift
# 设置first、step、last
if [ $# -eq 1 ];then
first=1
step=1
last=$1
elif [ $# -eq 2 ];then
first=$1
step=1
last=$2
elif [ $# -eq 3 ]; then
first=$1
step=$2
last=$3
else
echo "$FUNCNAME: ARGS wrong..."
exit 1
fi
# 最后一个要输出的元素及其长度,决定要填充多少个0
last_output=$[ last - ( last-first ) % step ]
zero_pad_len=`[ ${#last_output} -gt ${#first} ] && echo ${#last_output} || echo ${#first}`
# 生成序列数
if [ "x$zero_pad" = "xtrue" ];then
# 填充0
if [ $step -gt 0 ];then
# 递增,填充0
for((i=$first;i<=$last;i+=$step)){
[ $last_output -eq $i ] && { printf "%0${zero_pad_len}i\n" "$i";return; }
printf "%0${zero_pad_len}i " $i
}
else
# 递减,填充0
for((i=$first;i>=$last;i+=$step)){
[ $last_output -eq $i ] && { printf "%0${zero_pad_len}i\n" "$i";return; }
printf "%0${zero_pad_len}i " $i
}
fi
else
# 不填充0
if [ $step -gt 0 ];then
# 递增,不填充0
for((i=$first;i<=$last;i+=$step)){
[ $last_output -eq $i ] && { printf "%i\n" "$i";return; }
printf "%i " $i
}
else
# 递减,不填充0
for((i=$first;i>=$last;i+=$step)){
[ $last_output -eq $i ] && { printf "%i\n" "$i";return; }
printf "%i " $i
}
fi
fi
}
# 指定输出分隔符
: ${SEPARATOR="\n"}
# 输出结果
seq_func $ZERO_PAD $SEPARATOR $FIRST $INCREMENT $LAST | tr " " "$SEPARATOR"
上面解析选项的脚本缺陷在于无法解析FIRST为负数的情况,例如./seq.sh -w -5 3
将报错。但可以写为标准的./seq.sh -w -- -5 -3
语法。