Shell 腳本啟動如何傳遞參數

我們在日常的腳本開發中,經常會碰到當腳本需要輸入參數,然後腳本依據傳遞進來的參數作為依據,判斷執行接下來的腳本邏輯。今天就介紹一下給Shell腳本傳遞參數進行交互的幾種方式。

命令行參數

向腳本傳遞參數最基本的方式就是採用命令行參數。啟動腳本時,通過命令行將參數傳遞給腳本。具體的格式如下:

./my_shell_script param1 param2 #param1,2作為參數,通過命令行啟動腳本my_shell_script時傳遞給腳本。

那麼腳本如何解析傳遞進來的參數呢?這點和我們常見的C/C++程序類似,有過C++ main函數編寫經驗的夥伴應該知道,我們啟動main函數入口的exe 程序時,我們也採用類似的命令行參數傳遞方式,main函數接受傳遞進來的參數並放入參數數組中,其中exe文件的程序名會作為第一個參數放入參數數組中,而真正的函數參數會作為第二個元素放入數組中。在Shell 腳本中,參數解析是一樣的,只是沒有參數數組的概念。腳本中會將腳本文件名作為第一個參數,並用 $ 符號作為參數的引用。也就是說 $0 存儲著程序名,$1 存儲著腳本的第一個參數, $2 存儲著腳本的第二個參數,以此類推直到 $9. 上例子:

圖1

調用及輸出為:

./my_script helle #啟動腳本,並傳遞參數


the name of this/>the first parameter is helle
parameter 2 is null

示例比較簡單,不解釋了。值得注意的是,上面的例子中$0作為腳本名,獲得是包含路徑的字符串,如果希望只包含腳本文件名字而不包含路徑信息,則可以通過 $(basename $0)來只截取腳本名字。其次,我們在使用參數時,應該對參數是否有效做判斷,避免參數無效的情況。

bash>

移動變量

shift 命令用來移動參數變量,原理類似與數據結構中的具有FIFO特性的 queue, shift命令會讓參數左移,例如執行一次shift 命令, $2會移動到$1, $3移動到$2,以此類推,這對於參數遍歷,尤其不知道參數個數的情況下,非常有用。舉例:

圖2

調用及輸出為:

./my_script I am fine
parameter #1 = I
parameter #2 = am
parameter #3 = fine

上圖中可以看出,因為shift 命令,只用了$1變量,便實現了所有參數的遍歷,

參數選項

我們知道Linux 命令中,很多帶有參數選項,放在 '-'之後,例如 'ls -s',-s 就是命令ls的參數選項,那麼我們編寫的腳本也可以實現參數選項的格式。而這個關鍵在於如何解析傳遞進來的參數選項。下面就介紹一下具體的解析方法。

getopt 命令

getopt 命令是處理命令行選項和參數是非常便利的工具。格式為:

getopt optstring parameters

optstring是這條命令的關鍵,它定義了參數選項字母以及哪些選項字母需要參數值。

optstring 中列出所有選項字母,在需要參數值的選項字母后加一個冒號 ':' 作為標識。 例如

getopt ab:cd -a -b param1 -cd param2 param3
輸出為:-a -b test1 -c -d -- param2 param3

這條命令的含義是:腳本包含4個參數選項,其中-b後需要傳入參數值,-cd 被拆分成-c -d, 接著 '--' 雙橫線表示參數選項結束,其後面的param2 和 param3會作為參數傳遞給腳本。清楚了getopt 的規則後,我們看一下如何在腳本中使用。

腳本中使用 getopt 命令

圖3

調用與輸出:

./my_script -ab test1 -cd par1 par2
Found the -a option
Found the -b option and the parameter value is: 'test1'
Found the -c option
-d is not an option
Parameter #1: 'par1'
Parameter #2: 'par2'

腳本代碼稍顯複雜,我逐一講解:

首先看第2行 'set -- $(getopt -q ab:cd "$@")', set命令我之前的文章有講解過,該命令首先將腳本攜帶的命令選項和參數通過 getopt 格式化,然後將格式化的命令選項和參數通過set 設置為命令行值。有小夥伴注意到getopt 命令後面的 '-q',當輸入getopt 沒有定義的命令選項時,例如此處定義了ab:cd 四個命令選項,如果輸入e選項,getopt會返回 invalid異常,-q 可以忽略這種異常。

接下來是一個while循環,循環裡面是 case 分支語句,我們利用了shift 命令來保證新的參數只放在$1中,當遇到-a 選項時,執行對應的邏輯,此處我們輸出"Found the -a option"。當遇到-b 選項時,因為後面需要參數值,我們此時通過$2來存儲該參數值,並打印出來,注意:此處為什麼是$2呢,因為在每次case語句結束時,我們在15行,用了shift 語句pop掉當前的參數。接下來‘--’分支代表命令行參數結束,後面的內容是腳本參數,所以此處shift掉--自身,迎接接下來的腳本參數。*) 表示case 的 default 語句,碰到沒有定義的命令選項,提示"xx is not an option"

在後面就是處理腳本參數的邏輯,"$@"表示將腳本參數根據分隔符轉化為 list 傳遞給腳本。然後便利該參數腳本,輸出參數。

以上就是getopt 在腳本中基本的使用方式。

進階的 getopts 命令

注意,此處是getopts 命令,它的用法和getopt相似,但是增加了一些更便利的規則,它的格式為

getopts optstring variable

optstring 與 getopt相似,不同的地方是 getopt中 -q 來忽略選項不存在的錯誤變換為在optstring 前面添加 ":" ,getopts 會將當前參數保存在variable中。該命令也會用到兩個環境變量:OPTARG會保存命令選項後的參數值。OPTIND 會保存當前處理的參數位置。

圖4

調用及輸出為:

./my_script -ab test -cde p1 p2
Found the -a option
Found the -b option and the parameter value is: test
Found the -c option
d is not an option
? is not an option
Parameter #1: p1
Parameter #2: p2

圖4的代碼與圖3相似,其中第二行改為getopts 來處理命令選項和參數,"getopts :ab:cd opt" 第一個冒號表示忽略不存在的選項異常,opt用來存儲當前正在處理的參數值。case語句的每個分支中不需要‘-’開頭,處理b 命令選項時,通過環境變量 ‘$OPTARG’來獲取其後的參數值。 處理完命令選項後,要處理其後的參數,$OPTINT 存儲和當前處理的參數位置,所以我們可以通過shift 命令跳轉到參數的位置,然後就可以正常處理腳本參數了。

獲得用戶輸入

有時腳本運行過程中,需要人來輸入作為交互參數。具體方式包括:

read 命令

read variable #讀取用戶輸入,並存儲在variable中。

圖5

調用與輸出為:

./my_script


enter your name:Adam Kin
your name is Kin, Adam

超時處理

使用read命令時,如果一直沒有用戶輸入,腳本執行就會懸停,如果希望不管有沒有用戶輸入,腳本都能繼續執行,那麼可以通過 -t 指定超時時間,如果超時後仍無輸入,腳本可以繼續執行。

read -t 5 -p "enter your name:" name

以上面例子說明,當超過5秒沒有輸入後,read 返回非0碼,腳本繼續執行。

隱藏輸入信息

linux中輸入密碼的時候,我們知道shell中是沒有顯示的,就是利用了隱藏讀取輸入的命令

read -s -p "enter your password" pass #-s會隱藏輸入的信息。

具體例子就不列舉了,比較簡單,小夥伴可以自行在系統上嘗試一下。