亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

shell 命令行參數(getopt和getopts)

發布時間:2020-08-04 11:45:24 來源:網絡 閱讀:1573 作者:騎士救兵 欄目:系統運維

這里還有上一篇,這部分是基礎:
https://blog.51cto.com/steed/2443313

getopt 命令

使用getopt命令,可以解析任何命令行選項和參數,但是用法比較復雜。getopt的命令用法如下:

$ getopt --help

用法:
 getopt optstring parameters
 getopt [options] [--] optstring parameters
 getopt [options] -o|--options optstring [options] [--] parameters

選項:
 -a, --alternative            允許長選項以 - 開始
 -h, --help                   這個簡短的用法指南
 -l, --longoptions <長選項>  要識別的長選項
 -n, --name <程序名>         將錯誤報告給的程序名
 -o, --options <選項字符串>  要識別的短選項
 -q, --quiet                  禁止 getopt(3) 的錯誤報告
 -Q, --quiet-output           無正常輸出
 -s, --shell <shell>          設置 shell 引用規則
 -T, --test                   測試 getopt(1) 版本
 -u, --unquoted               不引用輸出
 -V, --version                輸出版本信息

$ 

用法一共有3種格式,下面都會用到。

在命令行中簡單使用

先看第一個最簡單的格式:

 getopt optstring parameters

第一部分是命令名。
第二部分optstring(選項字符串),是這個命令解析的格式。
第三部分parameters(getopt命令的參數),就是需要解析的內容。
因此,getopt會按照 optstring 的設置,將 parameters 解析為相應的選項和參數。參考示例來理解:

$ getopt ab:cd -ad value1 -b best1 value2 value3
 -a -d -b best1 -- value1 value2 value3
$ 

主要理解 ab:cd 的意義。
這里定義的都是短選項,4個字母代表有4個選項。b后面的冒號表示這個選項需要一個參數。如果不給選項b一個參數,就會報錯:

$ getopt ab:cd -ad value1 -b
getopt:選項需要一個參數 -- b
 -a -d -- value1
$ 

使用雙破折線
如果添加了雙破折線,那么無輪后面是什么,都會作為參數而不是選項來處理:

$ getopt ab:cd -- -ad value1 -b best1 value2 value3
 -- -ad value1 -b best1 value2 value3
$ getopt ab:cd -ad value1 -- -b best1 value2 value3
 -a -d -- value1 -b best1 value2 value3
$ 

這依然是是命令用法的第一種格式,雙破折線是parameters內容的一部分。
雙破折線出現位置之前的內容按照optstring的設置來解析,之后的內容一律認為是參數。即使有類似選項的內容,被認作為是參數。

參數包含空格的問題
第一種格式和第二、第三種在功能上也是有區別的。這里輸出的參數都是不帶引號的。而另外兩種格式輸出的參數都是帶引號的。
重要的區別不在引號上,而是這種用法不支持處理帶空格和引號的參數值。它會將空格當作參數分隔符,而不是根據雙引號將二者當作一個參數。

支持長選項

參考上面的示例,加上長選項的支持。使用長選項的示例如下:

$ getopt -o ab:cd --long arga,argb:,argc,argd -- -ad -b best --argd value1 value2
 -a -d -b 'best' --argd -- 'value1' 'value2'
$ 

這是命令用法的第三種格式。
-o 表示定義短選項
--long 其實是--longoptions,不過省略任意個字母程序都能認識。或者也可以用-l。這個是指定長選項的。所有內容都要連起來,不能有空格。選項之間用逗號隔開。定義完之后,在用雙破折號隔開,后面的內容就是parameters。

錯誤報告引用的程序名

之前已經試過一次解析錯誤的報告了:

$ getopt ab:cd -ad value1 -b
getopt:選項需要一個參數 -- b
 -a -d -- value1
$ 

這里錯誤報告的是getopt錯誤,可以把這個默認的內容替換掉。一般是換成執行的腳本的名字。
這里使用命令用法的第二種格式,把 optstring 和 parameters 都放到雙破折線后面:

$ getopt -- ab:cd -ad value1 -b best1
 -a -d -b 'best1' -- 'value1'
$ 

這樣在雙破折線前面就可加getopt命令的選項,這里要指定-n選項:

$ getopt -n test.sh -- ab:cd -ad value1 -b 
test.sh:選項需要一個參數 -- b
 -a -d -- 'value1'
$ 

這里看到包裹錯誤是,名字已經被替換掉了。
在腳本中,可以使用 $(basename $0) 或者直接用\$0。

禁止錯誤報告
還有一個-q參數,可以禁止錯誤報告,解析錯誤的選項和參數將被丟棄:

$ getopt -n test.sh -q -- ab:cd -ad value1 -b 
 -a -d -- 'value1'
$ 

可選參數

還有一種可選參數,使用兩個冒號。這個選項可以有一個或零個參數:

$ getopt -o a::bc: -l arga::,argb,argc: -- -a value1 --arga value2
 -a '' --arga '' -- 'value1' 'value2'
$ getopt -o a::bc: -l arga::,argb,argc: -- -avalue1 --arga=value2
 -a 'value1' --arga 'value2' --
$ 

第一次執行是傳遞的參數是錯誤的。因為是可選參數,參數和值之間不能有空格隔開,否則會有歧義。必須要連在一起才能認為是前一個選項的參數。否則就被認作是獨立的參數了。

小結

getopt 命令的選項所指定的選項字符串的規則:

  • 短選項,每一個字符代表一個選項
  • 長選項,每一個字符串代表一個選項,用逗號分隔
  • 選項后跟一個冒號,表示選項需要一個參數
  • 選項后跟兩個冒號,表示選項有一個可選參數(一個或零個參數)
  • 可選參數的參數和值之間不能有空格,短選項直接連起來,長選項加等號連起來

在腳本中使用 getopt

現在已經可以用getopt命令,將命令行參數按照規定的格式解析成規整的格式了。并且在解析過程中,還能發現參數格式錯誤的情況并報告。
接下來就是在腳本中使用經過getopt命令解析后的參數了。

set 命令

要在腳本中使用getopt。首先,要用getopt命令生成格式化后的版本來替換已有的命令行選項和參數。需要用到set命令。
set命令能夠處理shell中的各種變量。具體不展開,這里只用了這個命令的一個選項,雙破折線(--)。效果是將命令行參數替換成set命令的參數值。
然后,該方法會將原始腳本的命令行參數傳給getopt命令執行,之后再將getopt命令的輸出傳給set命令,用getopt格式化后的命令行參數來替換原始的命令行參數:

set -- $(getopt ab:cd "$@")

現在原始的命令行參數變量的值會被getopt命令的輸出替換。而getopt已經為我們格式化好了命令行參數。

直接使用

在之前編寫的腳本的基礎上,只要在開頭加上一行代碼,就可以直接使用了:

set -- $(getopt a:b:s:u "$@")

加上這句后,就是讓后續的代碼處理getopt返回的參數,而不是調用命令時的命令行參數。
驗證效果:

$ ./format.sh -u -a after -b befor value1 value2 value3
BEFOR_VALUE1_AFTER
BEFOR_VALUE2_AFTER
BEFOR_VALUE3_AFTER
$ ./format.sh -u -a after -b befor value1 "value2 value3" value4
BEFOR_VALUE1_AFTER
BEFOR_VALUE2_AFTER
BEFOR_VALUE3_AFTER
BEFOR_VALUE4_AFTER
$ 

第二條命令并不能處理帶空格的參數,因為這里使用的是getopt的第一種格式。

使用第二種格式來解析

要處理空格,就需要使用第二種格式(或者第三種),將命令修改為如下:

set -- $(getopt -- a:b:s:u "$@")

簡單的在最前面加上雙破折線就好了。這條語句是錯誤的,后面還要修改。

再來驗證一下:

$ ./format.sh -u -a after -b befor value1 "value2 value3" value4
'BEFOR'_'VALUE1'_'AFTER'
'BEFOR'_'VALUE2_'AFTER'
'BEFOR'_VALUE3'_'AFTER'
'BEFOR'_'VALUE4'_'AFTER'
$ 

使用第二、第三種格式,會用引號來限定參數的內容。但是引號干擾了set命令。

使用 eval 命令
這里出現了一個新的問題,不但沒有正確的處理空格,輸出的內容還有額外的引號。空格的問題先放一放,這里需要用到eval命令來解決新問題。

eval 命令用于將其后的內容作為單個命令讀取和執行,這里用于處理getopt命令生成的參數的轉義字符。

關于eval命令,還有一種使用的情景。有時候在腳本中拼接出來的字符串即使打印出來看正確。并且直接復制、粘貼在交互界面中也能正確讀被當做命令運行。但是卻無法在腳本中被執行。這個時候就可以使用eval命令來解決。它能夠把字符串當做命令來執行。
在腳本中通過各種引用和判斷拼接出一個復雜的命令的時候,有時候就會出現無法執行的情況。這時候就直接賦值、粘貼去交換界面試一下,如果拼接的結果本身沒問題,那么加上eval命令后,應該就能用運行。

修改命令如下:

eval set -- $(getopt -- a:b:s:u "$@")

再次驗證:

$ ./format.sh -u -a after -b befor value1 "value2 value3" value4
BEFOR_VALUE1_AFTER
BEFOR_VALUE2 VALUE3_AFTER
BEFOR_VALUE4_AFTER
$ 

第一種格式加上eval命令也是沒有問題的,所以可以無腦用上。

解決空格問題

只要能正確的使用getopt的第二種或第三種格式,那么參數包含空格的問題也就解決了。看上一小節。

參數解析錯誤并退出

執行命令時,使用錯誤的參數,當前的效果如下:

$ ./format.sh -u -w -a after -b befor value1 "value2 value3" value4
getopt:無效選項 -- w
BEFOR_VALUE1_AFTER
BEFOR_VALUE2 VALUE3_AFTER
BEFOR_VALUE4_AFTER
$ 

解析發現問題了,并且報告了,但是腳本沒有終止,而是繼續執行。如果要判斷出解析錯誤,就需要使用\$?參數。然后退出腳本則是用exit命令。
這里直接直接使用\$?并無法獲取到參數解析錯誤的結果。因為此時的結果是set命令(也可能是eval命令)的執行結果,而getopt是再前一條的命令。
解決這個問題,要先把getopt命令執行一遍,進行判斷。然后再用set調用一遍,可以直接使用之前執行的結果:

getopt_cmd=$(getopt -n $(basename $0) -- a:b:s:u "$@")
[ $? -ne 0 ] && exit 1
eval set -- "$getopt_cmd"

這里還加上了報告錯誤時名稱的定義。exit退出時也要指定退出狀態為非0,因為是運行錯誤。

驗證效果:

$ ./format.sh -v -a after -w -b
format.sh:無效選項 -- v
format.sh:無效選項 -- w
format.sh:選項需要一個參數 -- b
$ echo $?
1
$ 

現在解析有問題后,就會直接退出。

完整的代碼示例

這里加上長選項以及可選參數的功能。
多加了一個參數 -m, --mark 由于指定使用什么連接符:

  • 默認直接連,不使用連接符號
  • 加上選項,默認使用下劃線連接
  • 為選項加上參數后,則使用參數來連接

參數比較多,加了 -h, --help 選項打印參數說明。

完整代碼如下:

$ cat format.sh
#!/bin/bash
mark=""      # 連接符號
prefix=""    # 前綴
base="test"  # 默認字符串
suffix=""    # 后綴
upper=off    # 是否大寫
# 顯示聲明一下這是個數組變量,其實沒有必要
declare -a names  # 需要格式化輸出的所有原始字符串
# 打印的幫助信息
help_str="
參數說明:
  -h, --help:           打印幫助信息
  -m, --mark [連接符]:  使用連接符,默認是下劃線(_),可以指定
  -a, --after string:   添加后綴
  -b, --befor string:   添加前綴
  -s, --string string:  指定中間的字符串,默認是“test”
  -u, --upper:          全大寫輸出
"
# 解析命令行參數
getopt_cmd=$(getopt -o m::ha:b:s:u --long mark::,help,after:,befor:,string:,upper -n $(basename $0) -- "$@")
[ $? -ne 0 ] && exit 1
eval set -- "$getopt_cmd"
# 解析選項
while [ -n "$1" ]
do
    case "$1" in
        -m|--mark)
            case "$2" in
                "")
                    mark="_"
                    shift ;;
                *)
                    mark="$2"
                    shift ;;
            esac
            ;;
        -h|--help)
            echo -e "$help_str"
            exit ;;
        -a|--after)
            suffix="$2"
            shift ;;
        -b|--befor)
            prefix="$2"
            shift ;;
        -s|--string)
            base="$2"
            shift ;;
        -u|--upper)
            upper=on ;;
        --) shift
            break ;;
         *) echo "$1 is not an option"
            exit 1 ;;  # 發現未知參數,直接退出
    esac
    shift
done
# 解析參數
while [ -n "$1" ]
do
    names=("${names[@]}" "$1")
    shift
done
names[0]=${names[0]:-$base}
for name in "${names[@]}"
do
    # 添加前綴和后綴
    output="${prefix:+${prefix}${mark}}${name}${suffix:+${mark}${suffix}}"
    # 判斷是否要全大寫輸出
    if [ $upper = on ]
    then
        output=${output^^}
    fi
    # 輸出結果
    echo "$output"
done
$ 

驗證效果:

$ ./format.sh -a after -b befor VALUE1 "VALUE2 VALUE3" VALUE4
beforVALUE1after
beforVALUE2 VALUE3after
beforVALUE4after
$ ./format.sh -a after -b befor --mark 
befor_test_after
$ ./format.sh -a after -b befor --mark="||" -u
BEFOR||TEST||AFTER
$ ./format.sh -a after -b befor --mark="||" -u --help

參數說明:
  -h, --help:           打印幫助信息
  -m, --mark [連接符]:  使用連接符,默認是下劃線(_),可以指定
  -a, --after string:   添加后綴
  -b, --befor string:   添加前綴
  -s, --string string:  指定中間的字符串,默認是“test”
  -u, --upper:          全大寫輸出

$ 

有getopt就夠用了。順便再簡單講下getopts。
getopts功能上差一點,不過封裝的更高級,用起來更簡單,需要的代碼也會少一點。

getopts 命令

getopts是另一個解析命令行參數的工具。它是Bash的內部命令。
它的優勢在于:

  • 不需要通過一個外部程序來處理位置參數
  • 可以很容易地設置用來解析的Shell變量
  • getopts 定義在 POSIX 中

不支持長選項:

getopts 不能解析 GUN 風格的長選項(--long),也不能解析 XF86 風格的長選項(-long)

getopt 是將選項和參數處理后只生成一個輸出。我們還要用 set 來完成傳遞的工作。
getopts 能夠和已有的shell參數變量配合默契。每次調用時,一次只處理命令行上檢測到的一個參數。處理之后,它會退出并返回一個大于0的退出狀態碼。這樣就非常方便的可以在while循環中使用。

基本用法

getopts 會使用到一下3個變量:
OPTIND: 存放下一個要處理的參數的索引。這是 getopts 在調用過程中記住自己狀態的方式。
OPTARG: 由 getopts 找到的選項所對應的參數。
OPTERR: 值為0或1。指示Bash是否應該顯示由 getopts 產生的錯誤信息。

getopts 命令的基本語法:

getopts 選項字符串 名稱 [參數]

選項字符串(OPTSTRING):getopts 會有哪些選項,哪些是有參數的(選項后有冒號)
名稱(VARNAME):getopts 會將找到的選項賦值給這個名稱的變量
參數(ARGS):一般情況向缺省,getopts會去解析腳本調用時的所有的參數。如果執行了這個參數,getopts就不解析傳遞給腳本的參數了,而是解析這里的參數。

getopts 不會移動變量。在處理完所有的選項后,命令就會停止,并將參數留給我們來繼續處理。此時可以先用shit命令配合OPTIND的值來移動到第一個參數的位置:

shift $[ $OPTIND - 1 ]

錯誤報告模式

getopts命令支持兩種錯誤報告模式:

  • 詳細錯誤報告模式
  • 抑制錯誤報告模式

對于產品中的腳本,推薦使用抑制錯誤報告模式。

詳細錯誤報告模式
在詳細錯誤報告模式下,如果 getopts 遇到了一個無效的選項,VARNAME 的值會被設置為問號(?),并且變量 OPTARG 不會被設置。如果需要的參數沒找到,VARNAME的值也會被設置為問號(?),變量 OPRARG 也不會被設置,并且會打印一個錯誤信息。

抑制錯誤報告模式
在抑制錯誤報告模式下,如果 getopts 遇到一個無效的選項,VARNAME 的值會被設置為問號(?),并且變量 OPTARG 會被設置為選項字符。如果需要的參數沒找到,VARNAME的值會被設置為冒號(:),并且變量 OPTARG 中會包含選項字符。
要使用抑制錯誤報告模式,只需要在調用 getopts 時,設置選項字符串(OPTSTRING)時以冒號開頭即可。下面的例子用的就是一直錯誤報告模式。

示例代碼

這里使用抑制錯誤報告模式,所以需要自己分析并且報告解析錯誤。都在代碼里了:

$ cat say_hello.sh 
#!/bin/bash
defaultname="nobody"  # 默認的名字
declare -a names      # 存放名字的數組
hello="hello"         # 打招呼的用語
end="!"               # 結束的內容
tittle=off            # 是否首字母大寫
# 解析選項
while getopts :n:h:e:t opt
do
    case "$opt" in
        n) defaultname="$OPTARG" ;;
        h) hello="$OPTARG" ;;
        e) end="$OPTARG" ;;
        t) tittle=on ;;
        :)  # 沒有為需要參數的選項指定參數
            echo "This option -$OPTARG requires an argument."
            exit 1 ;;
        ?) # 發現了無效的選項
            echo "-$OPTARG is not an option"
            exit 2 ;;
    esac
done
# 解析參數
shift $[ $OPTIND -1 ]  # 移動到第一個參數的位置
# 這次用for循環遍歷
for arg in "$@"
do
    names=("${names[@]}" "$arg")
done
names[0]=${names[0]:-$defaultname}
for name in "${names[@]}"
do
    [ "$tittle" = on ] && output="${hello^} ${name^} $end" || output="$hello $name $end"
    echo "${output}"
done
$ 

驗證執行如下:

$ ./say_hello.sh 
hello nobody !
$ ./say_hello.sh -n adam
hello adam !
$ ./say_hello.sh -n adam -h hi -e. -t
Hi Adam .
$ ./say_hello.sh -h hi -e. -t adam bob clark
Hi Adam .
Hi Bob .
Hi Clark .
$ ./say_hello.sh -a -h hi -e. -t adam bob clark
-a is not an option
$ ./say_hello.sh -h
This option -h requires an argument.
$ 

選項和參數不能混排:

$ ./say_hello.sh adam
hello adam !
$ ./say_hello.sh adam -t
hello adam !
hello -t !
$ 

支持雙破折線:

$ ./say_hello.sh -t adam
Hello Adam !
$ ./say_hello.sh -t -- adam
Hello Adam !
$ 

比較下來,使用起來會比getopt方便很多,不過功能上也差了很多,可選參數(雙冒號::)應該也是不支持的。另外,如果熟悉getopt的話,每一步的操作都是自己的代碼控制的。而getopts就簡化了很多地方,比如不會調用shift移動變量。

將選項標準化

有些字母選項在Linux世界里已經有了某種程度的標準含義。如果在shell腳本中支持這些選項,就應該使用標準的字母來定義。
下面是一些命令行選項中經常會用到的選項和含義:
選項 描述
-a 顯示所有對象(顯示隱藏)
-c 生成一個計數
-d 指定一個目錄
-e 擴展一個對象
-f 指定讀入數據的文件
-h 顯示命令的幫助信息
-i 忽略文本大小寫
-l 產生輸出的長格式版本
-n 使用非交互模式(批處理)
-o 將所有輸出重定向到指定的輸出文件
-q 以安靜模式運行
-r 遞歸地處理目錄和文件
-s 以安靜模式運行
-v 生成詳細輸出
-x 排除某個對象
-y 對所有問題回答yes
向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

苏尼特左旗| 中江县| 那曲县| 罗源县| 射洪县| 芒康县| 五华县| 桃江县| 柏乡县| 清镇市| 天峨县| 闽清县| 澳门| 龙州县| 凭祥市| 阿拉善盟| 北流市| 海兴县| 广丰县| 新疆| 乌拉特前旗| 天柱县| 静海县| 永泰县| 临武县| 石渠县| 吴旗县| 马边| 六枝特区| 马公市| 荔波县| 桂东县| 德州市| 瑞昌市| 宁波市| 霸州市| 大理市| 民权县| 建昌县| 文山县| 怀宁县|