處理用戶輸入:
1、命令行參數
向shell腳本傳遞數據的最基本的方法是使用命令行參數,命令行參數允許在運行腳本時向命令行添加數據。
2、讀取參數
bash shell中有一些特殊變量叫做 位置參數,位置變量參數是標準的數字:$0 是程序名,$1 是第一個參數,$2是第二個參數,以此類推,直到第九個參數$9 ,$0~$9 可以定義在腳本中,通過命令行向其賦值。
當向shell腳本傳遞字符串時,如果希望將多個字符串當做一個變量,需要加上單引號 ' '
.
如果腳本需要的命令行參數不止9個,你仍然可以處理,但是需要稍微修改一下變量名,在第9個變量之後,你必須在變量數字周圍加上花括號,比如 ${ 10 }
3、讀取腳本名
可以使用$0 參數獲取shell在命令行啓動的腳本名,這在編寫多功能工具時很方便
(同樣的腳本如果需要根據不同的腳本名執行不同的功能時,就需要用到 $0 了)
但是出現一個潛在的問題,如果使用另一個命令來執行腳本,命令會和腳本名混合在一起出現出現在$0參數中
這不是唯一的問題,當傳給$0 變量的實際字符串不僅僅是腳本名,而是完整的腳本路徑時,變量$0就會使用整個路徑
解決這一問題可以使用basename命令,它會返回不包含路徑的腳本名
現在可以結和$0 和basename 來編寫基於腳本名執行不同功能的腳本了。
4、 特殊參數變量:
$# 含有腳本運行時攜帶的命令行參數的個數,可以在腳本中任何地方使用這個特殊變量,就跟普通變量一樣
基於$#實現特定功能:
5、 抓取命令行上提供的所有參數: $* $@
區別就是: $* 會將所有參數當成單個參數
$@ 會單獨處理每個參數
6、移動變量:
下面這個腳本通過shift命令實現了使用一個參數完成多個數據的遍歷,當第一個參數的長度爲0時,循環結束。測試完第一個參數後,shift命令會將所有的參數的位置移動一個位置。
( 要注意的是:使用shift命令時,一定要小心,如果某個參數被移出,它的值就被丟棄了,無法再恢復 )
留個小疑問:爲什麼 -n 判斷$1 是否爲0時要加上雙引號?
shift 也可以一次性移動多個位置,例如: shift 2 一次移動2
注意:我們來看下面這個例子,我特意檢測了一下當只有 一個特殊變量$1卻有多個參數時shift在while和case中的具體如何工作的
此時我們在腳本中先不使用shift,看看有多個選項時情況如何:
( 我們發現它會進行一個死循環,一直輸出-a 選項,不能夠讀取之後的選項 )
此時我們加上shift,重新運行你會發現一切正常
這說明 在while 和 case 中 ,每執行完一個選項,就需要shift一次,將原來的選項移出以此來讀取新的選項,這對我們理解接下來的 帶參數的選項很有幫助
7、 處理選項:
用一組普通的選項和參數來運行這個腳本,結果說明在處理時腳本認爲所有的命令行參數都是選項
當腳本遇到雙破折線時,它會停止處理選項,並將剩下的參數都當做命令行參數。
8、處理帶值的選項
有的選項會帶上一個額外的參數值,當命令行選項要求額外的參數時,腳本必須能檢測到並正確處理。
( 這種情況下,如$ ./testing.sh -a test1 -b -c -d test2 )
( 此處執行此腳本帶有命令行參數爲: ./difOption.sh -a -b test -c
如上文所說,先將 -a 存入$1變量,執行完-a 選項之後執行do的shift命令將-a 選項移出,遇到-b 選項將其存入$1,因爲-b選項帶有參數test,所以需要另外準備一個變量$2來存入參數值test,執行完-b選項之後,在-b選項之後執行一次shift將$1中的-b值移出,再在while循環最後執行一次shift將被移入$1的參數test也移出(所以此處是執行了兩次shift ),最後在將-c選項讀入$1變量,自後執行完畢退出)
9、使用getopt命令
9.1 命令的格式
getopt命令可以接受一系列任意形式的命令行選項和參數,並自動將它們轉換成適當的格式,其命令格式如下:
getopt optstring parameters
optstring 定義了命令行有效的選項字母,還定義了哪些選項字母需要參數值,在optstring中列出你要在腳本中用到的每個命令行選項字母,然後,在每個需要參數值的選項字母之後加一個冒號。getopt命令會基於你定義的optstring解析提供的參數
例如: $ getopt ab:cd -a -b test1 -cd test2 test3
( -a -b test1 -c -d -- test2 test3 )
optstring定義了四個有效選項字母:a、b、c、d,冒號(:)被放在了字母b後面,因爲b選項需要一個參數值,當getopt命令運行時,它會檢查提供的參數列表
( -a -b test1 -cd test2 test3 ),並基於提供的optstring進行解析。注意,它會自動將-cd 選項分成兩個單獨的選項,並插入雙破折線來分割行中的額外參數
如果指定了一個不在optstring中的選項,默認情況下,getopt會產生一條錯誤消息。
例如: $ getopt ab:cd -a -b test1 -cde test2 test3
9.2 在腳本中使用getopt
set -- $( getopt -q ab:cd "$@" )
雙破折線是set命令的的選項之一,它會將命令行參數替換成set命令的命令行值,然後該方法會將原始腳本的命令行參數傳給getopt命令,之後再將getopt命令的輸出傳給set命令,用getopt格式化後的命令行參數來替換原始的命令行參數。
getopt命令並不擅長處理帶空格和引號的參數值,它會將空格當做參數分隔符,而不是根據雙引號將兩者當做一個參數,我們可以使用getopts來解決這個問題。
10、使用getopts命令
每次調用getopts命令時,它一次只處理命令行上檢測到的一個參數,處理完所有的參數後,他會推出並返回一個大於0的退出狀態碼,這讓他非常適合用解析命令行所有參數的循環中。
getopts optstring variable
有效的選項字母都會列在optstring 中,如果選項字母要求有個參數值,就加一個冒號。要去掉錯誤消息的話,可以在optstring 之前加一個冒號。getopts命令將當前參數保存在命令行中定義的variable中。
getopts命令會用到兩個環境變量,如果選項需要跟一個參數值,OPTARG環境變量就會保存這個值,OPTIND環境變量保存了參數列表中getopts 正在處理的參數位置,這樣你就能在處理完選項之後繼續處理其他命令行參數了。
while語句定義了getopts命令,指明瞭要查找哪些命令行選項,以及每次迭代中存儲它們的變量名(opt),getopts命令解析命令行選項時會移除開頭的單破折線( 即運行腳本時的命令行參數的-a等。。),所以在case定義中不用單破折線
getopts對新手來說有幾個好用的功能
①可以在參數值中包括空格
②可以將選項字母和參數值放在一起使用,而不用加空格
③除此之外getopts還能夠將命令行上找到的所有未定義的選項統一輸出成問號
getopts命令知道何時停止處理選項,並將參數留給你處理。在getopts處理每個選項時,它會將OPTIND環境變量值增一,在getopts完成處理時,你可以使用shift命令和OPTIND值來移動參數。
現在你就擁有了一個能在所有shell腳本中使用的全功能命令行選項和參數處理工具
常用的linux命令選項 :
選項 |
描述 |
-a |
顯示所有對象 |
-c |
生成一個計數 |
-d |
指定一個目錄 |
-e |
擴展一個對象 |
-f |
指定讀入數據的文件 |
--help |
顯示命令的幫助信息 |
-i |
忽略文本大小寫 |
-l |
產生輸出的長格式文本 |
-n |
使用非交互模式(批處理) |
-o |
將所有輸出重定向到的指定的輸出文件 |
-q |
以安靜模式運行 |
-r |
遞歸的處理目錄和文件 |
-s |
以安靜模式運行 |
-v |
生成詳細輸出 |
-x |
排除某個對象 |
-y |
對所有問題回答yes |
11、獲得用戶輸入
11.1 基本的讀取
read命令從標準輸入(鍵盤)或另一個文件描述符中接受輸入。在收到輸入後,read命令會將數據放進一個變量。
此處的echo 使用了 -n選項,該選項不會在字符串末尾輸出換行符,允許腳本用戶緊跟其後輸入數據,而不是下一行,這讓腳本看起來更像表單
實際上,read 的選項 -p 也允許直接在read命令行指定提示符
read命令會將提示符後輸入的所有數據分配給單個變量,要麼你就指定多個變量,輸入的每個數據值都會分配給變量列表的下一個變量,如果變量數量不夠,剩下的數據就全部分配給最後一個變量
在read命令行中也可以不指定變量,如果是這樣,read命令會將它收到的任何數據都放進特殊環境變量REPLY中,REPLY環境變量會保存輸入的所有數據,可以在shell腳本中像其他變量一樣使用
11.2 超時
使用read命令時腳本很可能會一直苦等着腳本用戶的輸入,如果不管是否有數據輸入,腳本都必須繼續執行,你可以使用 - t 選項來指定一個計時器,-t 選項指定了read 命令等待輸入的秒數,當計時器過期後,read命令會返回一個非零退出狀態碼
如果計時器過期,read命令會以非零退出狀態碼退出,可以使用if - then 或 while 循環這種標準的結構化語句來理清所發生的具體情況,在本例中,計數器過期時,if語句不成立,shell會執行else部分的命令
也可以讓read命令來統計輸入的字符數,當輸入的字符達到預設的字符數時,就自動退出,將輸入的數據賦給變量
本例中將-n 選項和值1一起使用,告訴read命令在接受單個字符後退出,只要按下單個字符回答後,read命令就會接受輸入並將它傳給變量,無需按回車鍵
11.3 隱藏方式讀取
有時候你需要從腳本用戶處獲得輸入,但是又不能在屏幕上顯示輸入信息,典型的例子就是輸入密碼,除此之外還有很多其他需要隱藏的數據類型。
read命令的-s 選項可以避免在read 命令中輸入的數據出現在顯示器上(實際上,數據會被顯示,只是read命令會將文本顏色設成跟背景色一樣)
11.4 從文件讀取
也可以用read命令來讀取linux系統上文件裏保存的數據,每次調用read命令,它都會從文件中讀取一行文本,當文件在沒有內容時,read命令會退出並返回非零退出狀態碼。
最常見的搭配是對文件使用cat 命令 ,將結果通過管道直接傳給含有read命令的while 命令
while循環會持續通過read命令處理文件中的行,直到read命令以非零退出狀態碼退出。