第十三章:處理使用者輸入
命令列參數
讀取參數
bash shell會將一些稱為位置參數(positional parameter)的特殊變數分配給命令列輸入的所有參數
甚至包括程式名
$0:程式名(程式的絕對路徑),可以對$0使用basename函數(basename $0),它只返回程式名
$i(9>i>0):第i個參數
如果需要的參數多於9個,那麼只需${10},這樣既可
如果指令碼需要參數,但是執行的時候並沒有輸入參數,執行的時候則會得到錯誤
if [ -n "$1" ]……
應該先檢查是否有參數,然後再做處理
特殊參數變數
$#:參數數量
${!#}:最後一個參數。花括弧({})中不允許使用貨幣符號($),這裡使用驚嘆號(!)
所以下面的代碼是錯誤的
#!/bin/bashecho We have "$#" "parameter(s)"echo The last parameter is "${$#}" # wrong wayecho The last parameter is "${!#}" # right way
執行結果:
$ param_test 1 1 1 5We have 4 parameter(s)The last parameter is 1535The last parameter is 5
注意:當命令列沒有任何參數時,$#返回0,而${!#}返回函數名
提取命令列上的所有參數
$*:將命令列上提供的所有參數當做1個單詞儲存
$@:所有參數的集合
#!/bin/bashecho "\$* and \$@ test"echo "\$* is:"$* #這裡兩個輸出結果是一樣的echo "\$@ is:"$@ #count=0for var in "$*"do count=$[$count+1] echo "$count:"$vardoneecho "\$* done."count=0for var in "$@"do count=$[$count+1] echo "$count:"$vardoneecho "\$@ done."
輸出結果:
$* and $@ test$* is:a b c$@ is:a b c1:a b c$* done.1:a2:b3:c$@ done.
移動資料
shift
將每個變數的位置都提前一個,$0不變,$1被移除。
count=1while [ -n "$1" ]do echo "Paramter #$count=$1" count=$[$count + 1] shiftdone
注意:當參數被移除之後,無法恢複。
處理選項
while [-n $1 ]do case "$1" in -a) echo "Found the -a option" ;; -b) echo "Found the -b option" ;; *) echo "$1 is not a option" ;; esac shiftdone
分離參數和選項
Linux利用雙破折線(--)表明選項結束。
#!/bin/bashwhile [ -n "$1" ]do case "$1" in -a) echo "Found option a";; -b) echo "Found option b";; --) shift break;;#跳出while,而不是case *) echo "$1 not a option";; esac shiftdonefor p in $@do echo "$p is a param ."done
處理帶值的選項
#!/bin/bashwhile [ -n "$1" ]do case "$1" in -a) echo "option a" ;; -b) echo "option b. $2 is a param." #如果找到選項b,那麼此時$2就應該是選項b的值 shift;; #p281頁,原文為shift 2,實際不需要,因為並沒有break出迴圈 --) shift break;; -c) echo "option c" ;; *) echo "$1 is not a option. ";; esac shiftdone
getopt
文法:
getopt
options optstring parameters在
optstring中列出所有選項,帶值選項要在字母后加冒號(:),如果參數中包含無效參數,那麼會給出錯誤資訊
$ getopt ab:cd -a -b pb -cde p1 p2getopt: invalid option -- 'e' -a -b pb -c -d -- p1 p2
-q:屏蔽錯誤報表
$ getopt -q ab:cd -a -b pb -cde p1 p2 -a -b 'pb' -c -d -- 'p1' 'p2'
set -- command:set會將命令列參數替換為set命令列的值。set -- `getopt ab:cd "$@"`getopt將參數格式化好了之後,由set替換掉命令列原始參數。將下面指令碼儲存到檔案getopt_test中
#!/bin/bashset -- `getopt a:b:c "$@"`echo "param = $@"while [ -n "$1" ]do case "$1" in -a) echo "found option a and param = $2" shift ;; -b) echo "found option b and param = $2" shift ;; -c) echo "found option c, no param." ;; --) ;; *) echo "what's this?" break ;; esac shiftdone
下面是運行結果
$ getopt_test -a test -b test -egetopt: invalid option -- 'e'param = -a test -b test --found option a and param = testfound option b and param = test
可以看出,
getopt 可以識別出未知選項但是,它還是有些不足
下面是一個沒有正確提供選項的例子
$ getopt_test -a -b -cparam = -a -b -c --found option a and param = -bfound option c, no param.
這裡將-b識別為-a的參數了,當然這是因為使用者輸入不正確導致的。但是getopt並沒有正確的識別出來
再看一個參數中含有空格的例子
$ getopt_test -a "x y"param = -a x y --found option a and param = xwhat's this?
顯然這裡getopt錯把"x y"當成了兩個參數/選項最後一個問題,我們可以用下面的命令解決
getopts
文法:
getopts
optstring variable
getopts用到的兩個環境變數
OPTARG:如果選項需要跟著有一個參數值,那麼此變數就儲存這個參數值
OPTIND:儲存getopts正在處理的參數的位置
注意:如果想屏蔽錯誤訊息,需要在optstring前面加冒號,而不是使用-q
getopts將當前參數儲存在命令列中定義的variable中
每調用一次getopts,它只處理命令列中的一個參數,處理完所有參數後,它會退出並返回一個大於0的退出狀態代碼
#!/bin/bashwhile getopts abc:d optdo case $opt in a) echo "option -a found";; b) echo "option -b found";; c) echo "option -c found and param = $OPTARG";; d) echo "option -d found";; ?) p=$[$OPTIND-1] echo "what's this? "${!p} echo "what's this? "$opt;; esacdone
這裡與getopt不同,getopts會自動移出“-”,所以case中就不要加“-”了輸出結果
$ param_test -a -b -c "a param" -d -eoption -a foundoption -b foundoption -c found and param = a paramoption -d found./param_test: illegal option -- ewhat's this? -ewhat's this? ?
getopts將不認識的選項一律以問號輸出,所以最後一行我們會多看到一個問號
將選項標準化下面是一些命令中選項的常用的含義(原文為通用,其實並不是很通用)
選項 |
描述 |
-a |
顯示所有對象 |
-c |
產生一個計數 |
-d |
指定一個目錄 |
-e |
擴充一個對象 |
-f |
指定讀取資料的檔案 |
-h |
顯示命令的協助資訊 |
-i |
忽略文字大小寫 |
-l |
產生輸出的長格式版本 |
-n |
使用非互動模式(批量) |
-o |
指定將所有輸出重新導向到的輸出檔案 |
-q |
以安靜模式運行 |
-r |
遞迴處理目錄和檔案 |
-s |
以安靜模式運行 |
-v |
產生詳細輸出 |
-x |
排除某個對象 |
-y |
對所有問題回答yes |
獲得使用者輸入 read:接受從標準輸入(鍵盤)或另一個檔案描述符的輸入在收到輸入後,read命令會將資料放進一個標準變數
#!/bin/bashecho -n "Enter your name:"read nameecho "Hello $name"read -p "Enter your age:" ageecho "You are $age years old..."
echo的-n選項會移除末尾的換行-p:可以指定提示句可以將輸入儲存到多個變數中,如果變數表中變數不夠用,之後的輸入將都儲存到最後一個變數中
read -p "What would you like to eat?" f1 f2echo "you would like to eat $f1 and $f2"
如果不給read指定變數,那麼read到的內容將儲存到REPLY環境變數中-t:指定逾時時間,單位為秒逾時之後,read會返回一個非0的退出狀態代碼
#!/bin/bashread -n1 -p "Are you a boy?" answerechocase $answer iny|Y) echo "Oh, you're a boy.";;N|n) echo "Oh, you are not a boy.";;esac
-n number:當輸入達到number個字元的時候,read結束,並將結果賦給變數上面樣本中,當輸入了一個字元後,程式將自動運行,不需要使用者輸入斷行符號確定-s:隱藏方式讀取(其實是將文字顏色設定為背景色而已)
#!/bin/bashwhile read -n1 -s cdo echo -n "*"done
輸入的字元以*替代,當然,上面的例子中,如果輸入退格鍵,*號是不會刪除,依然繼續增加……
從檔案中讀取
read將一次讀取檔案中的一行,當讀取完畢的時候,read會退出並返回非0狀態代碼
#!/bin/bashcount=0while read linedo count=$[ $count + 1 ]done < $1echo "$count line(s) in all."
如果用管道給read傳送資料,將會開啟一個子shell,這樣在while外再查看$count,會發現它依然為0
轉貼請保留以下連結
本人blog地址
http://su1216.iteye.com/
http://blog.csdn.net/su1216/