天天看點

shell程式設計——getopt設計執行個體使用getopt設計shell腳本選項示例

使用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

文法。