引言
前面介紹了bash編程的基礎變量與算術表達式,本文介紹在腳本中的進階知識:測試
在bash中測試大體分兩部分:條件測試、組合測試。
而條件測試有分:數值測試、字符串測試、文件測試。
組合測試則有兩種表達方式。具體是什麼表達方式在文章中會有具體展示。
本文實驗環境為CentOS7.2
Linux中為什麼要學習測試(判斷)?
當我第一次學習這部分內容時,覺得好難,好不爽。可是這又是想要繼續學習Linux必須要掌握的知識點。為什麼?我們在生活中面對各種選擇時總要問問自己,我是否應該怎樣,不這樣會發生什麼,在生活中就有諸多類似的“測試”,工作中也離不開,而我們學習Linux掌握這門技術是為了更好的工作,Linux的學習自然也離不開“測試”。當然這麼說還有些抽象,那麼就舉個具體的例子:接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”。
如果你沒有學過測試那麼此時別人讓你寫這麼一個腳本供他使用,你怎麼辦?
在正式介紹測試前,我們需要先介紹下在測試中必備的數學知識:邏輯運算
邏輯運算:
邏輯運算在希臘時期就已經出現,不過它正式被運用於數字電路及計算機則是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或!很多時可以使用這種表示方式,這兩種是等價的
測試表達式:
測試表達式分三種:
1、test EXPRESSION
2、[ EXPRESSION ]
3、[[ EXPRESSION ]]
上面三種使用各有其適用范圍,限於所學有限沒有能力對其進行一一歸納,我覺得剛開始學不需要求全責備,先掌握大體知識框架比較好。之後在實際中遇到再慢慢進行總結。腳本寫的多,遇到的問題多,這三種的使用場景自然就心領神會了。
條件測試:數值測試、字符串傳測試、文件測試
數值測試:判斷兩個數值的大小及是否相等,有如下
-gt:是否大於 大於為真,否則為假
-ge:是否大於等於 大於等於為真,否則為假
-eq:是否等於 等於為真,否則為假
-ne:是否不等於 不等於為真,否則為假
-lt:是否小於 小於為真,否則為假
-le:是否小於等於 小於等於為真,否則為假
下面是一個小例子顯示其簡單用法,$?是執行狀態返回值,可以查看上一條命令執行結果的真與假,0表示為真,1-255為假。
1 2 3[root@localhost
test
]
# [ 1 -eq 2 ]
[root@localhost
test
]
# echo $?
1
我們判斷1是否等於2,狀態返回值為1判斷執行結果為假,所以1不等於2.
………………………………………………………………………………………………………………………
字符串測試:判斷字符串是否符合或等於給定的字符串
字符串的判斷大小是依據ASCII中字符對應的數字大小進行
==:是否等於 等於為真,否則為假
>:是否大於 大於為真,否則為假
<:是否小於 小於為真,否則為假
!=:是否不等於 不等於為真,否則為假
=~:左側字符串是否能夠被右側的PATTERN(正則表達式)所匹配 若匹配則為真,否則為假
-z “string” : 測試字符串是否為空,空則為真,否則為假
-n “string” :測試字符串是否不為空,不空為真,否則為假
下面也舉一個簡單的例子展示字符串測試用法
1 2 3 4 5 6 7 8 9 10[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加""結果報錯,之後又加了[]才未報錯。這裡我們可以看到在字符串測試中使用[[ ]]方式進行會比較靠譜,但也不一定。用[]還是[[ ]]就是在這種測試中摸索出來的。
下面再對字符是否為空舉一個例子
1 2 3 4 5 6 7[root@localhost
test
]
# name1=
[root@localhost
test
]
# [ -z $name1 ]
[root@localhost
test
]
# echo $?
0
[root@localhost
test
]
# [ -n $name1 ]
[root@localhost
test
]
# echo $?
0
怎麼會出現這種情況?字符測試為空竟然不靈!別慌,上面我們曾有經驗,字符測試如果單中括號失敗那就試試雙中括號
1 2 3 4 5 6[root@localhost
test
]
# [[ -z $name1 ]]
[root@localhost
test
]
# echo $?
0
[root@localhost
test
]
# [[ -n $name1 ]]
[root@localhost
test
]
# echo $?
1
結果終於如願,上面的兩個例子告訴我們,當測試結果並不是對時,調整下中括號往往有奇效。
………………………………………………………………………………………………………………………
文件測試:
1、存在性測試
-a FILE (少用)
-e FILE 文件存在性測試,存在為真,否則為假
1 2 3 4 5 6[root@localhost
test
]
# [ -e /etc/fstab ]
[root@localhost
test
]
# echo $?
0
[root@localhost
test
]
# [[ -e /etc/ftab ]]
[root@localhost
test
]
# echo $?
1
2、存在性及類別測試
-b FILE:是否存在且為塊設備文件,存在為真否則為假
-c FILE:是否存在且為字符設備文件,存在為真,否則為假
-f FILE:是否存在且為普通文件,存在為真,否則為假
-d FILE:是否存在且為目錄文件,存在為真,否則為假
-h FILE 或 -L FILE :是否存在且為鏈接文件,存在為真,否則為假
-p FILE:是否存在且為命名管道文件,存在為真,否則為假
-S FILE:是否存在且為套接字文件,存在為真,否則為假
1 2 3 4 5 6[root@localhost
test
]
# [ -f /test/if1 ]
[root@localhost
test
]
# echo $?
0
[root@localhost
test
]
# [ -f /test/ ]
[root@localhost
test
]
# echo $?
1
3、文件權限測試
-r FILE:是否存在且對當前用戶可讀,存在為真,否則為假
-w FILE:是否存在且對當前用戶可寫,存在為真,否則為假
-x FILE:是否存在且對當前用戶可執行,存在為真,否則為假
1 2 3 4 5[root@localhost
test
]
# echo $USER
root
[root@localhost
test
]
# [ -r /test/ ]
[root@localhost
test
]
# echo $?
0
4、文件特殊權限測試
-g FILE:是否存在且擁有sgid,存在為真,否則為假
-u FILE:是否存在且擁有suid,存在為真,否則為假
-k FILE:是否存在且擁有sticky,存在為真,否則為假
1 2 3 4 5[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
5、文件大小測試
-s FILE:是否存在且非空,存在為真,否則為假
1 2 3 4 5 6 7[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
6、文件時間戳測試
-N FILE:文件自上一次被讀取之後是否被修改過,被修改過為真,否則為假
選取剛剛被修改過得file1測試
1 2 3[root@localhost
test
]
# [ -N /test/file1 ]
[root@localhost
test
]
# echo $?
0
7、文件從屬關系測試
-O FILE:當前用戶是否為文件的屬主,是為真,否為假
-G FILE:當前用戶是否屬於文件的屬組,是為真,否為假
1 2 3 4 5[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
8、雙目測試
FILE1 -ef FILE2 :FILE1與FILE2是否指向同一個文件系統的相同inode的硬鏈接,是則為真,否為假
FILE1 -nt FILE2 :FILE1的mtime是否新於FILE2,是為真,否為假
FILE1 -ot FILE2 :FILE1的mtime是否舊於FILE2,是為真,否為假
1 2 3[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
第一種表達方式:
1[root@localhost
test
]
# [[ 1 -lt 2 ]] && [[ name == Name ]]
第二種表達方式:
1 2 3 4[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。
運行腳本
1、賦予執行權限,並直接運行此程序文件常見格式為:./文件名
2、直接運行解釋器,將腳本以命令參數傳遞給解釋器程序:bash <腳本文件>
腳本實例
1、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小於1,則提示用戶“至少應該給一個參數”,並立即退出;如果參數個數不小於1,則顯示第一個參數所指向的文件中的空白行數
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15[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,數值測試,組合測試,變量引用
2、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法並退出,是,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16[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通給出相應提示,這個腳本的大致思路就是這樣。
關於腳本的個人感受
寫腳本前先要理清楚思路,這個問題要怎麼解決,對哪些內容要進行測試,都需要用到哪些測試方法,需要設置哪些變量,用到哪些組合測試...
上述確定後就開始寫,寫完再進行調試。很多時候就算自己想的都沒錯,可是腳本寫完依舊不能成功執行或達成想要的結果,因為初學總會出現各種意料不到的情況比如[]與[[ ]]的錯誤使用,比如命令引用忘記加``等等細節。