歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux bash腳本編程初級-邏輯運算與測試

引言

前面介紹了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通給出相應提示,這個腳本的大致思路就是這樣。


關於腳本的個人感受

寫腳本前先要理清楚思路,這個問題要怎麼解決,對哪些內容要進行測試,都需要用到哪些測試方法,需要設置哪些變量,用到哪些組合測試...

上述確定後就開始寫,寫完再進行調試。很多時候就算自己想的都沒錯,可是腳本寫完依舊不能成功執行或達成想要的結果,因為初學總會出現各種意料不到的情況比如[]與[[ ]]的錯誤使用,比如命令引用忘記加``等等細節。

Copyright © Linux教程網 All Rights Reserved