在編寫shell腳本中,經常要處理一些輸入參數,在使用過程中發現getopts更加方便,能夠很好的處理用戶輸入的參數和參數值。
getopts用於處理用戶輸入參數,舉例說明使用方法:
while getopts :a:b:cdefg opt; do
case $opts in
a) do sth;
......
cde) do another;
esac
done
幾個重要變量:
OPTIND:getopts使用OPTIND作為索引,來處理下一個需要處理的參數,記錄當前的狀態。
OPTARG:在上面的循環中,a,b兩個參數後面各有一個冒號,冒號表示該輸入的參數後面還有一個參數值,當getopts發現冒號後,會處理用戶輸入的參數值,這個參數值被保存在OPTARG中。
OPTSTRING:也就是上例中的 :a:b:cdefg,getopts需要處理的參數。注意,最前面的冒號“:”用於指定getopts工作於silent mode,在silent模式下,當用戶輸入的參數不滿足OPTSTRING時,不會講illegal option這樣的錯誤信息打印出來,使代碼看起來更加專業。如果想要工作在verbose模式下,可以去掉最前面的冒號
下面,簡單的寫了一個shell腳本用來描述getopts的使用方法:
#! /bin/bash
function c1() {
cmd="rhc app create -p RedHat"
while getopts :a:t:sn opt; do
case $opt in
a) cmd=$cmd" -a $OPTARG" ;;
t) cmd=$cmd" -t $OPTARG" ;;
s) cmd=$cmd" -s" ;;
n) cmd=$cmd" -n --no-dns" ;;
\?) echo "Invalid param" ;;
esac
done
echo $cmd
}
c1 -a app1 -t perl-5.10 -s -n
執行這個腳本,我們就會得到預期的結果
[root@linuxidc shell]# ./getopts-silent.sh
rhc app create -p redhat -a app1 -t perl-5.10 -s -n --no-dns
當然,有些時候,我們更新網將function寫入.bashrc中,方便自己隨時調用,如果將這段代碼直接粘貼到.bashrc中,可能會引起問題:我沒有得到預期的結果,腳本中的cmd並沒有按照預想的情況得到處理,這是因為什麼呢?
原因在於,保存在.bashrc後,第一次執行完成後,下一次在執行時,OPTIND不會重新產生,因為他被作為一個global variable使用,所以getopts在調用時,他的索引會變得混亂。在腳本中執行沒有遇到這個問題的原因也在此,因為腳本每次執行時,都會調用一個 新的shell,所以OPTIND會被設置為1。如果想要他在.bashrc中生效,必須要在最上面加上local OPTIND
讓我們來稍微修改一下:
# Create apps
function create-apps() {
local OPTIND
cmd="rhc app create -p $OPENSHIFT_PASSWD"
while getopts a:t:sn x
do
case $x in
a) cmd=$cmd" -a $OPTARG" ;;
t) cmd=$cmd" -t $OPTARG" ;;
s) cmd=$cmd" -s" ;;
n) cmd=$cmd" -n --no-dns" ;;
\?) echo Invalid Params ;;
esac
done
echo $cmd
}
source之後,我們可以直接調用,看一下是否達到了我們預期的結果:
[root@linuxidc shell]# create-apps -a free -t jbsseap -n
rhc app create -p redhat -a free -t jbsseap -n --no-dns
如果還不是很了解,你可以簡單的看下這個例子,這個例子是如果傳遞進來的參數包括f,那麼執行對應代碼:
while getopts "dfiPRrvW" opt //賦值給opt
do
case $opt in
f) //如果傳遞進來是f
exec $realrm "$@"
;;
*)
# do nothing //傳遞其他參數,包括d,i,p,r,v,w
;;
esac
done