使用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
文法。