運行指令碼時的命令列參數,如
./myscript.sh -a -b arg
在指令碼中通常是用case語句處理。我個人比較喜歡的做法:首先盡量使用長參數名(短參數名通常意義不明顯,畢竟你的指令碼沒有這麼流行),比如
./myscript --with-ssl=yes --install-dir=../export
再在指令碼中通過下面的函數處理參數
################################################################################# 分析命令列,如果命令列中有選項(作為函數第1個實參):# --xxx-x-x=vvv# 則這個函數執行__xxx_x_x=vvv,即,相當於將vvv賦值給__xxx_x_x變數# 如果命令列中的選項不包含'='號,則這個函數將命令列參數插入第2個實參代表的變數中# 以供稍後處理################################################################################function ParseOption(){ if [ $# -gt 0 ]; then if [ "${1:0:2}" = "--" ]; then local key=${1%%=*} if [ "${key}" != "${1}" ]; then local value=${1#*=} key=${key//-/_} eval ${key}=${value} return 0 elif [ -n "${key}" ] && [ -n "${2}" ]; then eval ${2}+=\" ${1}\" return 0 else return 1 fi elif [ -n "${2}" ]; then eval ${2}+=\" ${1}\" return 0 else return 1 fi else return 1 fi}arguments=for option in $*do ParseOption ${option} argumentsdone
arguments可以稍後拿來做case處理,但對於賦值型命令列參數,這種處理方式擴充性非常好。
比如,我們的指令碼要跟svn打交道,有下面的語句:
svn update
但我在其它機器上運行這個指令碼時,發現它的svn沒有安裝在系統路徑,需要使用全路徑引用。我只需要簡單的修改這行代碼為
${__svn:-svn} update
不用添加任何多餘的代碼,指令碼就可以支援通過命令列參數的方式指定svn路徑,即
./myscript --svn=/opt/subversion/bin/svn ...
相當方便。通過這種方式,添加命令列參數的支援不再麻煩,指令碼只需要正確使用變數即可。
另外,一些“動態命名”的參數,用case也難以處理,如
./build-tool ... --platforms=st5197,st7105 --st5197-config=st5197_setenv.sh --st7105-config=st7105_setenv.sh
上述命令的意思是,我們的平台指定了st5197和st7105,同時,這兩個平台都有預先處理指令碼,在我們的進行正式工作前要去執行(比如說一些環境變數的設定)。這些指令碼的數量不定(對應於--platforms指定的平台數),就是說,--platforms指定了4個平台,後面可能會有4個--{platform}-config(也可能少於4個,表明相應平台不需要預先處理指令碼);同時,指定的這些參數要能夠與相應的平台聯絡起來,這就是為什麼我們在選項命名上與平台關聯起來(也就是說,這些選項命名不是預先確定的)。
在Shell指令碼中,可以對上面的參數做如下處理
for platform in ${__platforms}do #如果命令列指定了參數--{platform}-config=FILE,則在上述ParseOption()裡__{platform}_config變數已被賦上值,將這個值轉存到platform_config變數裡以方便後面引用 eval platform_config='$'__${platform}_config if [ -n "${platform_config}" ]; then ... fidone
可以簡單的擷取平台對應的config檔案名稱,並加以處理。