如何在 Bash shell 腳本中解析命令行選項(xiàng)
- 給你的 shell 腳本添加選項(xiàng)。
終端命令通常具有 選項(xiàng)或開關(guān),用戶可以使用它們來(lái)修改命令的執(zhí)行方式。關(guān)于命令行界面的 POSIX 規(guī)范 中就對(duì)選項(xiàng)做出了規(guī)范,這也是最早的 UNIX 應(yīng)用程序建立的一個(gè)由來(lái)已久的慣例,因此你在創(chuàng)建自己的命令時(shí),最好知道如何將選項(xiàng)包含進(jìn) Bash 腳本 中。
與大多數(shù)語(yǔ)言一樣,有若干種方法可以解決 Bash 中解析選項(xiàng)的問題。但直到今天,我最喜歡的方法仍然是我從 Patrick Volkerding 的 Slackware 構(gòu)建腳本中學(xué)到的方法,當(dāng)我第一次發(fā)現(xiàn) Linux 并敢于冒險(xiǎn)探索操作系統(tǒng)所附帶的純文本文件時(shí),這些腳本就是我的 shell 腳本的引路人。
Bash 中的選項(xiàng)解析
在 Bash 中解析選項(xiàng)的策略是循環(huán)遍歷所有傳遞給 shell 腳本的參數(shù),確定它們是否是一個(gè)選項(xiàng),然后轉(zhuǎn)向下一個(gè)參數(shù)。重復(fù)這個(gè)過程,直到?jīng)]有選項(xiàng)為止。
- #!/bin/bash
- while [ True ]; do
- if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
- ALPHA=1
- shift 1
- else
- break
- fi
- done
- echo $ALPHA
在這段代碼中,我創(chuàng)建了一個(gè) while 循環(huán),它會(huì)一直進(jìn)行循環(huán)操作,直到處理完所有參數(shù)。if 語(yǔ)句會(huì)試著將在第一個(gè)位置($1)中找到的參數(shù)與 --alpha 或 -a 匹配。(此處的待匹配項(xiàng)是任意選項(xiàng)名稱,并沒有特殊意義。在實(shí)際的腳本中,你可以使用 --verbose 和 -v 來(lái)觸發(fā)詳細(xì)輸出)。
shift 關(guān)鍵字會(huì)使所有參數(shù)位移一位,這樣位置 2($2)的參數(shù)移動(dòng)到位置 1($1)。處理完所有參數(shù)后會(huì)觸發(fā) else 語(yǔ)句,進(jìn)而中斷 while 循環(huán)。
在腳本的末尾,$ALPHA 的值會(huì)輸出到終端。
測(cè)試一下這個(gè)腳本:
- $ bash ./test.sh --alpha
- 1
- $ bash ./test.sh
- $ bash ./test.sh -a
- 1
可以看到,選項(xiàng)被正確地檢測(cè)到了。
在 Bash 中檢測(cè)參數(shù)
但上面的腳本還有一個(gè)問題:多余的參數(shù)被忽略了。
- $ bash ./test.sh --alpha foo
- 1
- $
要想捕獲非選項(xiàng)名的參數(shù),可以將剩余的參數(shù)轉(zhuǎn)儲(chǔ)到 Bash 數(shù)組 中。
- #!/bin/bash
- while [ True ]; do
- if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
- ALPHA=1
- shift 1
- else
- break
- fi
- done
- echo $ALPHA
- ARG=( "${@}" )
- for i in ${ARG[@]}; do
- echo $i
- done
測(cè)試一下新版的腳本:
- $ bash ./test.sh --alpha foo
- 1
- foo
- $ bash ./test.sh foo
- foo
- $ bash ./test.sh --alpha foo bar
- 1
- foo
- bar
帶參選項(xiàng)
有一些選項(xiàng)需要傳入?yún)?shù)。比如,你可能希望允許用戶設(shè)置諸如顏色或圖形分辨率之類的屬性,或者將應(yīng)用程序指向自定義配置文件。
要在 Bash 中實(shí)現(xiàn)這一點(diǎn),你仍然可以像使用布爾開關(guān)一樣使用 shift 關(guān)鍵字,但參數(shù)需要位移兩位而不是一位。
- #!/bin/bash
- while [ True ]; do
- if [ "$1" = "--alpha" -o "$1" = "-a" ]; then
- ALPHA=1
- shift 1
- elif [ "$1" = "--config" -o "$1" = "-c" ]; then
- CONFIG=$2
- shift 2
- else
- break
- fi
- done
- echo $ALPHA
- echo $CONFIG
- ARG=( "${@}" )
- for i in ${ARG[@]}; do
- echo $i
- done
在這段代碼中,我添加了一個(gè) elif 子句來(lái)將每個(gè)參數(shù)與 --config 和 -c 進(jìn)行比較。如果匹配,名為 CONFIG 的變量的值就設(shè)置為下一個(gè)參數(shù)的值(這就表示 --config 選項(xiàng)需要一個(gè)參數(shù))。所有參數(shù)都位移兩位:其中一位是跳過 --config 或 -c,另一位是跳過其參數(shù)。與上節(jié)一樣,循環(huán)重復(fù)直到?jīng)]有匹配的參數(shù)。
下面是新版腳本的測(cè)試:
- $ bash ./test.sh --config my.conf foo bar
- my.conf
- foo
- bar
- $ bash ./test.sh -a --config my.conf baz
- 1
- my.conf
- baz
Bash 讓選項(xiàng)解析變得簡(jiǎn)單
還有一些其他方法也可以解析 Bash 中的選項(xiàng)。你可以替換使用 case 語(yǔ)句或 getopt 命令。無(wú)論使用什么方法,給你的用戶提供選項(xiàng)都是應(yīng)用程序的重要功能,而 Bash 讓解析選項(xiàng)成為了一件簡(jiǎn)單的事。