分支迴圈是程式語言重要結構,它使得計算機源源不斷地給搬磚。Shell 中也有對應語法支援。

在分支迴圈結構中,判斷條件十分重要,在 Shell 中可以用test函式來判斷條件。

1 test函式

test在 Shell 用於測試判斷,如其名字所示,它可以進行一些測試,如:

  • 兩個字串是否相等
  • 給定路徑是否存在
  • 路徑是否有各種權限

語法如下:

test condition
test $a -eq 5

判斷為邏輯真,返回0,判斷值為假返回值1。返回值不能用e=$(test $a -eq 5)來獲取,這樣運算後e是空。而要用$?的方式來獲取。$?用於獲取上一條命令的返回值。

test 1 -eq 2
echo $? # output 1, which means false
test 1 -eq 1
echo $? # output 0, which means true

test的返回值可以作為條件判斷(如if else)的條件:

if test "${a}" -eq 5; then echo $a; fi

test命令也可以用單中括號([])來代替,只是使用單中括號時候,需要注意在中括號和條件之間必須有空格( )。

if [ -e ex ]; then echo "exist ex"; else echo "not exist ex"; fi
if test -e ex; then echo "exist ex"; else echo "not exist ex"; fi

1.1 路徑判斷

Linux 中檔案不一定有副檔名,檔案和資料夾的名字沒有區別。

函式意義
-e路徑存在(檔案或資料夾)則返回 true,否則 false,e 是 exist 的意思
-d路徑存在且是資料夾則返回 true,否則 false,d 是 directory 的意思
-f路徑存在且是檔案則返回 true,否則 false,f 是 file 的意思
-n路徑存在且大小不為零則返回 true,否則 false,n 是 nonzero 的意思
-z路徑存在且大小為零則返回 true,否則 false,z 是 zero 的意思
-L/-h路徑存在且是連結則返回 true,否則 false,L 是 link 的意思
-r路徑存在且有 read 權限則返回 true,否則 false,r 是 read 的意思
-w路徑存在且有 write 權限則返回 true,否則 false,w 是 write 的意思
-x路徑存在且有 execute 權限則返回 true,否則 false,x 是 execute 的意思
if [ -e $a ]; then echo "exist $a"; fi
if [ -d $a ]; then echo "exist directory $a"; fi
if [ -f $a ]; then echo "exist file $a"; fi
if [ -n $a ]; then echo "$a is not None"; fi
if [ -z $a ]; then echo "$a is  None"; fi
if [ -L $a ]; then echo "exist link $a"; fi
if [ -r $a ]; then echo "$a has read access"; fi
if [ -w $a ]; then echo "$a has write access"; fi
if [ -x $a ]; then echo "$a has execute access"; fi

1.2 檔案比較

test命令也可以用於兩個檔案的比較。

函式意義
patha -nt pathbpatha修改時間比pathb新則返回 true,否則 false,nt 是 newer than 的意思
patha -ot pathbpatha修改時間比pathb舊則返回 true,否則 false,ot 是 older than 的意思
patha -ef pathbpathapathb有相同 device 和 innode number 則返回 true,否則 false
if test $a -nt $b; then echo "$a is newer than $b"; fi
if test $a -ot $b; then echo "$a is older than $b"; fi

1.3 整數比較

下面針對的是整數判斷,如果不是整數,則會報錯。

函式意義|
-eq兩整數相等則返回 true,否則 false,eq 是 equal 的意思,若輸入不是倆整數,則報錯
-gt兩整數前者大於後者則返回 true,否則 false,gt 是 greater than 的意思,若輸入不是倆整數,則報錯
\>含義同-gt,為了和重定向符號區分,則需要轉義
-ltlt 是 less than 的意思
\<-lt
-gege 是 greater eqaul 的意思,注意沒有\>=這種寫法
-lege 是 less eqaul 的意思,注意沒有\<=這種寫法
if test $a -eq $b; then echo "$a eqals $b"; fi

1.4 字串不相等判斷

=!=針對字串。字串完全相同則是相等,有一點不同則是不等。

函式意義|
=兩字串相同則返回 true,否則 false,判斷字串的等號左右都是有空格的
!=兩字串不同則返回 true,否則 false,gt 是 greater than 的意思,若輸入不是倆整數,則報錯
if test $a = $b; then echo "$a eqals $b"; fi

2 分支結構

就是條件判斷,在不同條件下執行不同的操作。常見有if elsedo whilecase esac這幾種。

2.1 if else結構

if condition; then xxx; fi
if condition; then xxx; else yyy; fi
if condition_1; then xxx; elif condition_2;then yyy; else zzz; fi

2.2 case esac結構

如果有多個選項,可以用一堆if elif else,也可以用case esac的結構。 這個和 c 語言中的switch case是一樣的。不過這個esac是個什麼鬼?看看if結尾的fi就能大霧了。🐶

語法如下:

case $x in
1) echo "select 1";;
2) echo "select 2";;
3) echo "select 3";;
*) echo "select nothing";;
esac

最後的星號*表示啥也沒有選到,預設值。最後兩個分號(;;)是跳出當前case esac的意思,和其它語言中的break很相似。不過 shell script 本身就是有breakcontinue關鍵字的,和 c 語言中的關鍵字是一樣的。

3 迴圈結構

常見的迴圈結構有forwhileuntil三種:

for x in xxxx;
do
xyz_operation
done
while condition:
do
xyz
done
until condition
do
xyz
done

如果要一直執行,則可以使用while true死迴圈一直執行。

continue是跳出當前迴圈,繼續下一次迴圈的意思。 break是跳出整個迴圈。

當然continuebreak都可以在後面接一個數字n,表示是跳出當前第n層迴圈的意思。

4 條件邏輯運算

4.1 分支中的條件運算

Shell 中表示式的結果可以進行與或非邏輯連線:

函式含義
-a/&&邏輯與
-o/||邏輯或
!邏輯非
if [ x -eq 5 ] && [ y -eq 6]; then echo "help"; fi
if test x -eq 5 && test y -eq 6; then echo "help"; fi
if ![ x -eq 5 ]; then echo "help"; fi

4.2 條件級連運算

對於命令也可以進行邏輯運算。

command_1 && command_2

這裡還有一個好處,如果command_1已經返回邏輯假,則command_2就可以不執行了。

if [ ! -d ${path1} ]; then
mdkir -p ${path1}
fi

上面的寫法就可以簡寫:

[ ! -d ${path1} ] && mkdir -p ${path1}

同樣,對於或運算而言,如果第一個條件滿足,後面的就不會執行了。這樣的寫法可以使程式碼更加簡潔。

總結

本文介先紹了 Shell 中的test命令,用於判斷各種情況,然後介紹了 Shell 中的分支迴圈語法,以及條件級連運算。