引言node
前面介紹了bash編程的基礎變量與算術表達式,本文介紹在腳本中的進階知識:測試正則表達式
在bash中測試大致分兩部分:條件測試、組合測試。shell
而條件測試又分:數值測試、字符串測試、文件測試。編程
組合測試則有兩種表達方式。具體是什麼表達方式在文章中會有具體展現。bash
本文實驗環境爲CentOS7.2框架
Linux中爲何要學習測試(判斷)?
ide
當我第一次學習這部份內容時,以爲好難,好不爽。但是這又是想要繼續學習Linux必需要掌握的知識點。爲何?咱們在生活中面對各類選擇時總要問問本身,我是否應該怎樣,不這樣會發生什麼,在生活中就有諸多相似的「測試」,工做中也離不開,而咱們學習Linux掌握這門技術是爲了更好的工做,Linux的學習天然也離不開「測試」。固然這麼說還有些抽象,那麼就舉個具體的例子:接受一個主機的IPv4地址作爲參數,測試是否可連通。若是能ping通,則提示用戶「該IP地址可訪問」;若是不可ping通,則提示用戶「該IP地址不可訪問」。學習
若是你沒有學過測試那麼此時別人讓你寫這麼一個腳本供他使用,你怎麼辦?測試
在正式介紹測試前,咱們須要先介紹下在測試中必備的數學知識:邏輯運算
ui
邏輯運算:
邏輯運算在希臘時期就已經出現,不過它正式被運用於數字電路及計算機則是20世紀的一我的物:香農。他在其碩士論文中提出將布爾代數應用於電子領域的概念,並給出可以構建任何邏輯和數值關係的邏輯電路的解決方法。有了香農的貢獻纔有了現在的計算機。
邏輯運算主要包括三種:與或非,以後在這三種基礎上又出現了異或(這裏再也不介紹)。
在Linux中與或非的運算符號爲:
與 : && 在測試命令中有時也會用-a表示與
或 : || 在測試命令中有時也會用-o表示或
非 : !
與、或、非運算:
與運算: 1 && 1 = 1 1 && 0 = 0
或運算: 1 || 1 = 1 1 || 0 = 1 0 || 1 = 1 0 || 0 = 0
非運算: ! 1 = 0 ! 0 = 1
在計算機中因爲用1表示真,0表示假,故上面的三種運算也能夠看作以下概念:
與運算: 真 && 真 = 真 真 && 假 = 假
或運算: 真 || 真 = 真 真 || 假 = 真 假 || 真 = 真 假 || 假 = 假
非運算: ! 真 = 假 ! 假 = 真
在測試中經常使用的邏輯運算中的定律
德摩根定律:
非(P 且 Q)=(非 P)或(非 Q)
非(P 或 Q)=(非 P)且(非 Q)
它在測試中的做用:一般爲了化簡邏輯表達式。
好比在一個測試表達式中出現了多個-a或-o使用德摩根定律能夠減小其個數
! a == b -a ! c == d -a ! d == a 等價於!( a == b -o c == d -o d == a )
當前面-not或!不少時可使用這種表示方式,這兩種是等價的
測試表達式:
測試表達式分三種:
一、test EXPRESSION
二、[ EXPRESSION ]
三、` EXPRESSION `
上面三種使用各有其適用範圍,限於所學有限沒有能力對其進行一一概括,我以爲剛開始學不須要求全責備,先掌握大致知識框架比較好。以後在實際中遇到再慢慢進行總結。腳本寫的多,遇到的問題多,這三種的使用場景天然就心照不宣了。
條件測試:數值測試、字符串傳測試、文件測試
數值測試:判斷兩個數值的大小及是否相等,有以下
-gt:是否大於 大於爲真,不然爲假
-ge:是否大於等於 大於等於爲真,不然爲假
-eq:是否等於 等於爲真,不然爲假
-ne:是否不等於 不等於爲真,不然爲假
-lt:是否小於 小於爲真,不然爲假
-le:是否小於等於 小於等於爲真,不然爲假
下面是一個小例子顯示其簡單用法,$?是執行狀態返回值,能夠查看上一條命令執行結果的真與假,0表示爲真,1-255爲假。
[root@localhost test]# [ 1 -eq 2 ] [root@localhost test]# echo $? 1
咱們判斷1是否等於2,狀態返回值爲1判斷執行結果爲假,因此1不等於2.
………………………………………………………………………………………………………………………
字符串測試:判斷字符串是否符合或等於給定的字符串
字符串的判斷大小是依據ASCII中字符對應的數字大小進行
==:是否等於 等於爲真,不然爲假
>:是否大於 大於爲真,不然爲假
<:是否小於 小於爲真,不然爲假
!=:是否不等於 不等於爲真,不然爲假
=~:左側字符串是否可以被右側的PATTERN(正則表達式)所匹配 若匹配則爲真,不然爲假
-z 「string」 : 測試字符串是否爲空,空則爲真,不然爲假
-n 「string」 :測試字符串是否不爲空,不空爲真,不然爲假
下面也舉一個簡單的例子展現字符串測試用法
[root@localhost test]# [ a == b ] [root@localhost test]# echo $? 1 [root@localhost test]# [ a < b ] -bash: b: 沒有那個文件或目錄 [root@localhost test]# [ "a" < "b" ] -bash: b: 沒有那個文件或目錄 [root@localhost test]# [[ "a" < "b" ]] [root@localhost test]# echo $? 0
這裏我先對ab是否相等進行判斷,以後查看結果是假,也就是a不是b。以後對其進行大小判斷,而後報錯,先爲ab加""結果報錯,以後又加了[]才未報錯。這裏咱們能夠看到在字符串測試中使用` `方式進行會比較靠譜,但也不必定。用[]仍是` `就是在這種測試中摸索出來的。
下面再對字符是否爲空舉一個例子
[root@localhost test]# name1= [root@localhost test]# [ -z $name1 ] [root@localhost test]# echo $? 0 [root@localhost test]# [ -n $name1 ] [root@localhost test]# echo $? 0
怎麼會出現這種狀況?字符測試爲空居然不靈!別慌,上面咱們曾有經驗,字符測試若是單中括號失敗那就試試雙中括號
[root@localhost test]# [[ -z $name1 ]] [root@localhost test]# echo $? 0 [root@localhost test]# [[ -n $name1 ]] [root@localhost test]# echo $? 1
結果終於如願,上面的兩個例子告訴咱們,當測試結果並非對時,調整下中括號每每有奇效。
………………………………………………………………………………………………………………………
文件測試:
一、存在性測試
-a FILE (少用)
-e FILE 文件存在性測試,存在爲真,不然爲假
[root@localhost test]# [ -e /etc/fstab ] [root@localhost test]# echo $? 0 [root@localhost test]# [[ -e /etc/ftab ]] [root@localhost test]# echo $? 1
二、存在性及類別測試
-b FILE:是否存在且爲塊設備文件,存在爲真不然爲假
-c FILE:是否存在且爲字符設備文件,存在爲真,不然爲假
-f FILE:是否存在且爲普通文件,存在爲真,不然爲假
-d FILE:是否存在且爲目錄文件,存在爲真,不然爲假
-h FILE 或 -L FILE :是否存在且爲連接文件,存在爲真,不然爲假
-p FILE:是否存在且爲命名管道文件,存在爲真,不然爲假
-S FILE:是否存在且爲套接字文件,存在爲真,不然爲假
[root@localhost test]# [ -f /test/if1 ] [root@localhost test]# echo $? 0 [root@localhost test]# [ -f /test/ ] [root@localhost test]# echo $? 1
三、文件權限測試
-r FILE:是否存在且對當前用戶可讀,存在爲真,不然爲假
-w FILE:是否存在且對當前用戶可寫,存在爲真,不然爲假
-x FILE:是否存在且對當前用戶可執行,存在爲真,不然爲假
[root@localhost test]# echo $USER root [root@localhost test]# [ -r /test/ ] [root@localhost test]# echo $? 0
四、文件特殊權限測試
-g FILE:是否存在且擁有sgid,存在爲真,不然爲假
-u FILE:是否存在且擁有suid,存在爲真,不然爲假
-k FILE:是否存在且擁有sticky,存在爲真,不然爲假
[root@localhost test]# [ -g /test/if1 ] [root@localhost test]# echo $? 1 [root@localhost test]# ll /test/if1 -rwxr-xr-x. 1 root root 149 8月 15 10:34 /test/if1
五、文件大小測試
-s FILE:是否存在且非空,存在爲真,不然爲假
[root@localhost test]# [ -s /test/file1 ] [root@localhost test]# echo $? 1 [root@localhost test]# echo > file1 [root@localhost test]# [ -s /test/file1 ] [root@localhost test]# echo $? 0
六、文件時間戳測試
-N FILE:文件自上一次被讀取以後是否被修改過,被修改過爲真,不然爲假
選取剛剛被修改過得file1測試
[root@localhost test]# [ -N /test/file1 ] [root@localhost test]# echo $? 0
七、文件從屬關係測試
-O FILE:當前用戶是否爲文件的屬主,是爲真,否爲假
-G FILE:當前用戶是否屬於文件的屬組,是爲真,否爲假
[root@localhost test]# [ -O /test/if1 ] [root@localhost test]# echo $? 0 [root@localhost test]# ll /test/if1 -rwxr-xr-x. 1 root root 149 8月 15 10:34 /test/if1
八、雙目測試
FILE1 -ef FILE2 :FILE1與FILE2是否指向同一個文件系統的相同inode的硬連接,是則爲真,否爲假
FILE1 -nt FILE2 :FILE1的mtime是否新於FILE2,是爲真,否爲假
FILE1 -ot FILE2 :FILE1的mtime是否舊於FILE2,是爲真,否爲假
[root@localhost test]# [ /test/if1 -nt /test/file1 ] [root@localhost test]# echo $? 1
由於file1剛剛被修改過,因此它比if1文件的mtine要新,由於使用-nt故測試結果爲假
組合測試
第一種方式:
與 COMMAND1 && COMMAND2 第一條命令爲假後再也不執行第二條命令,爲真方執行。
或 COMMAND1 || COMMAND2 第一條命令爲真後再也不執行第二條命令,爲假方執行。
非 ! COMMAND 對命令結果的真假取反
第二種方式:
EXPRESSION -a EXPRESSION 第一條命令爲假後再也不執行第二條命令,爲真方執行。
EXPRESSION -o EXPRESSION 第一條命令爲真後再也不執行第二條命令,爲假方執行。
! EXPRESSION 對命令結果的真假取反
示例:比較1是否比2小若其爲真則進而比較字符name是否等於Name
第一種表達方式:
[root@localhost test]# [[ 1 -lt 2 ]] && [[ name == Name ]]
第二種表達方式:
[root@localhost test]# [[ 1 -lt 2 -a name == Name ]] -bash: 條件表達式中有語法錯誤 -bash: `-a' 附近有語法錯誤 [root@localhost test]# [ 1 -lt 2 -a name == Name ]
用[]仍是` `有時真的須要一遍遍的測試。
腳本實踐
簡要介紹下腳本相關內容
shell腳本也屬於一種語言,這種語言屬於弱類型,不須要聲明數據的存儲格式,bash中均當作字符處理,它靠解釋器運行。
寫腳本前須要在所打開文件第一行頂格給出shebang,解釋器路徑對於bash就是#!/bin/bash。
運行腳本
一、賦予執行權限,並直接運行此程序文件常見格式爲:./文件名
二、直接運行解釋器,將腳本以命令參數傳遞給解釋器程序:bash <腳本文件>
腳本實例
一、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑做爲參數;若是參數個數小於1,則提示用戶「至少應該給一個參數」,並當即退出;若是參數個數不小於1,則顯示第一個參數所指向的文件中的空白行數
[root@localhost test]# cat scrip1 #!/bin/bash # [ $# -lt 1 ] && echo "At least provide one path" && exit 1 lines_space=`grep '^$' $1 | wc -l` [ $# -eq 1 ] && echo "The space lines of the first file are :$lines_space" [ $# -gt 1 ] && echo "None message" && exit 2 [root@localhost test]# chmod +x scrip1 [root@localhost test]# ./scrip1 /etc/fstab The space lines of the first file are :1 [root@localhost test]# ./scrip1 /etc/fstab /etc None message [root@localhost test]# ./scrip1 At least provide one path
腳本中用到了特殊變量$#,位置變量$1,數值測試,組合測試,變量引用
二、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址作爲參數,先判斷是否合格IP,否,提示IP格式不合法並退出,是,測試是否可連通。若是能ping通,則提示用戶「該IP地址可訪問」;若是不可ping通,則提示用戶「該IP地址不可訪問」
[root@localhost test]# cat scrip2 #!/bin/bash # [ $# -lt 1 ] && echo "please give one IP address" && exit 1 [ $# -gt 1 ] && echo "this script just match one IP address" && exit 2 [ $# -eq 1 ] && [[ $1 =~ (([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4])\.){3}([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-4]) ]] && ping -c 1 $1 | sed -n '2p'|grep -o '^64' >> /dev/null && echo "該IP地址可訪問" || echo "該IP地址不可訪問" [root@localhost test]# chmod +x scrip2 [root@localhost test]# ./scrip2 please give one IP address [root@localhost test]# ./scrip2 192.168.1.1 該IP地址不可訪問 [root@localhost test]# ./scrip2 192.168.85.3 該IP地址可訪問 [root@localhost test]# ./scrip2 192.168.85.3 192.168.168.1 this script just match one IP address
上面思路,先判斷參數個數,也就是是否在腳本後加IP。而後判斷IP是否符合規範,以後進行若IP可ping通給出相應提示,這個腳本的大體思路就是這樣。
關於腳本的我的感覺
寫腳本前先要理清楚思路,這個問題要怎麼解決,對哪些內容要進行測試,都須要用到哪些測試方法,須要設置哪些變量,用到哪些組合測試...
上述肯定後就開始寫,寫完再進行調試。不少時候就算本身想的都沒錯,但是腳本寫完依舊不能成功執行或達成想要的結果,由於初學總會出現各類意料不到的狀況好比[]與` `的錯誤使用,好比命令引用忘記加``等等細節。