shell腳本編程筆記(三)—— 流程控制之分支結構

命令流程通常有三種 —— 順序、分支及循環,順序沒啥好說的,流程控制的重點在於分支和循環結構。

在瞭解這兩個結構之前,補充一個知識點 —— 退出狀態碼

一、 退出狀態碼

1. 含義及查看方法

shell中運行的每個命令其實都有退出狀態碼,退出狀態碼是0~255之間的整數值,在命令結束時傳給shell,標誌命令是否正常執行。0表示正常,其餘數字表示各種各樣的異常,常見如下:

狀態碼

描述

0

命令成功結束

1

一般性未知錯誤

2

不適合的shell命令

126

命令不可執行

127

沒找到命令

128

無效的退出

128+x

與Linux信號x相關的嚴重錯誤

130

通過ctrl+c終止的命令

255

正常範圍之外的退出狀態碼

 

 

 

 

 

 

 

 

 

 

Linux提供了一個專門的變量$?保存最近一個已執行命令的退出狀態碼

echo $?

2. 設置方法

默認情況下,shell腳本會以最後一個命令的退出狀態碼退出,也可以使用exit命令自己設置。設置範圍應該在0~255之間,如果大於255,返回的數值會是 設置值%256得到的結果。

可以稍微改下前面的腳本

#!/bin/bash
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(echo "scale=4; $var1*$var2+$var3*$var4" | bc)
echo The final answer is $var5
exit 5

還可以使用變量作爲exit的參數

#!/bin/bash
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(echo "scale=4; $var1*$var2+$var3*$var4" | bc)
echo The final answer is $var5
exit $var4

下面正式來看分支結構

 

二、 if命令

1. 格式與簡單用法

if分支的結構如下所示

#格式1
if commands
then
    commands
elif commands
then
    commands
else
    commands
fi

#格式2,then與if在同一行,注意有分號
if commands;then
    commands
elif commands;then
    commands
else
    commands
fi

與一般編程語言使用表達式判斷不同,shell的if可以使用命令,原理就是使用前面的退出狀態碼,如果狀態碼爲0則執行then後面的語句。例如

#!/bin/bash

myuser=oracle
if grep $myuser /etc/passwd
then
    echo "The user $myuser exists on the system"
else
    echo "The user $myuser doesn't exist on the system"
fi

這種直接在if中判斷命令的其實用的也不多,注意還是使用表達式判斷,常見有以下三種:

  • 數值判斷
  • 字符串判斷
  • 文件判斷

2. 數值判斷

寫法較多,每種也有各自優缺點:

  • 方法一: if [ $A -lt $B ]; then ...

    -eq(等於)、-ne(不等於)、lt(小於)、gt(大於)、le(小於等於)、ge(大於等於);缺點:只能比較整數,使用lt,gt等不直觀

  • 方法二: if ((A < B)) then ...

優點:簡單易理解,允許使用高級數學表達式(例如++、--、位運算、與或非等);缺點:還是隻能比較整數

  • 方法三: if (echo $A $B | awk '!($1>$2){exit 1}') then ...

使用awk比較,優點:可以比較小數;缺點:表達式複雜,難記

  • 方法四: if (echo $A - $B | bc -q | grep -q "^-"); then ...

使用bc比較,優點:可以比較小數;缺點:表達式更復雜,難記

以下例子判斷指定變量是否爲偶數

#!/bin/bash

INT=-5
if [[ ${INT} =~ ^-?[0-9]+$ ]];then #爲整數
    if [ ${INT} -eq 0 ];then
        echo "the INT is zero."
    else
        if [ ${INT} -lt 0 ];then
            echo "the INT is negative."
        else 
            echo "the INT is positive."
        fi
        if [ $((INT % 2)) -eq 0 ];then
            echo "the INT is even."
        else
            echo "the INT is odd."
        fi
    fi
else
    echo "the INT is not an integer."
    exit 1
fi

也可以用上面的方法二

#!/bin/bash

INT=-5
if [[ ${INT} =~ ^-?[0-9]+$ ]];then
    if ((INT == 0));then
        echo "INT is zero"
    else
        if ((INT < 0));then
            echo "INT is negative"
        else
            echo "INT is postive"
        fi
        if (( ((INT % 2)) == 0));then
            echo "INT is even"
        else
            echo "INT is odd"
        fi
    fi
else
    echo "INT is not aninteger"
    exit 1
fi

 

3. 字符串判斷

  • =或==:等於,if [ "$a" = "$b" ] 或 if [ "$a" == "$b" ]
注意==在[[]]和[]中的行爲是不同的,[[]]提供模式匹配功能
1. [[ $a == z* ]] # 如果$a以"z"開頭(模式匹配)那麼將爲true
2. [[ $a == "z*" ]] # 如果$a等於z*(字符匹配)那麼結果爲true
3. [ $a == z* ] # 將會發生File globbing 和word splitting
4. [ "$a" == "z*" ] # 如果$a等於z*(字符匹配)那麼結果爲true
  • != 不等於,if [ "$a" != "$b" ], 這個操作符將在[[]]結構中使用模式匹配.
  • < 小於,根據ASCII字母順序比較大小,if [[ "$a" < "$b" ]] 或 if [ "$a" \< "$b" ] (在[]結構中"<"需要被轉義)
  • > 大於,根據ASCII字母順序比較大小,if [[ "$a" > "$b" ]] 或 if [ "$a" \> "$b" ] (在[]結構中"<"需要被轉義)
  • -z 字符串爲空或長度爲0
  • -n 字符串不爲空、長度不爲0
#!/bin.bash

# test string : evaluate the value  of a string
ANSWER="maybe"
if [ -z ${ANSWER} ];then
    echo "there is no answer." >&2
    exit 1
fi
if [ ${ANSWER} == "yes" ];then
    echo "the answer is yes."
elif [ ${ANSWER} == "no" ];then
    echo "the answer is no."
elif [ ${ANSWER} == "maybe" ];then
    echo "the answer is maybe."
else
    echo "the answer is unknown."
fi

 

4. 文件判斷

  • -e 判斷對象是否存在
  • -d 判斷對象是否存在,並且爲目錄
  • -f 判斷對象是否存在,並且爲常規文件
  • -L 判斷對象是否存在,並且爲符號鏈接
  • -h 判斷對象是否存在,並且爲軟鏈接
  • -s 判斷對象是否存在,並且長度不爲0(即文件是否不爲空)
  • -r 判斷對象是否存在,並且可讀
  • -w 判斷對象是否存在,並且可寫
  • -x 判斷對象是否存在,並且可執行
  • -O 判斷對象是否存在,並且屬於當前用戶
  • -G 判斷對象是否存在,並且屬於當前用戶組
  • -nt 判斷file1是否比file2新  [ "/data/file1" -nt "/data/file2" ]
  • -ot 判斷file1是否比file2舊  [ "/data/file1" -ot "/data/file2" ]
#!/bin/bash
# test-file: Evaluate the status of a file
FILE=~/.bashrc
if [ -e "$FILE" ];then //-e判斷是否存在這個文件
    if [ -f "$FILE" ];then
        echo "$FILE is a regular file"
    fi
    
    if [ -d "$FILE" ];then
        echo "$FILE is a directory"
    fi
    
    if [ -r "$FILE" ];then
        echo "$FILE is readable"
    fi
    
    if [ -w "$FILE" ];then
        echo "$FILE is writable"
    fi
    
    if [ -x "$FILE" ];then
        echo "$FILE is executable"
    fi
    
else
    echo "$FILE does not exist"
    exit 1
fi  
exit  

着重說一下最後的exit,exit後面不帶參數,默認退出狀態爲0,如果這個命令出現在腳本的最後一行,默認退出狀態以0終止,但是上面這個腳本如果判斷出文件不存在,直接就以1退出了,不會運行最後一行的exit
如果我們把上面的shell腳本里的內容變成一個函數,同時要求當目標文件不存在的時候返回狀態值1

test_file () {
if ...
...
...
else
    echo "$FILE does not exist"
    return 1
fi
}

 

5. 複合條件判斷

即與、或、非

判斷符號 含義 舉例
-a 或 && 邏輯與,前面的表達式爲真纔會執行後面的代碼 [ 1 -eq 1 -a 1 -ne 0 ] 或者 [ 1 -eq 1 ] && [ 1 -ne 0 ]
-o 或 || 邏輯或,前面的表達式爲假纔會執行後面的代碼 [ 1 -eq 1 -o 1 -ne 0 ] 或者 [ 1 -eq 1 ] || [ 1 -ne 0 ]
! 邏輯非,對錶達式取反 if [ ! 表達式 ]

 

 

 

 

 

例1:

#!/bin/bash

MIN_VAL=1
MAX_VAL=100
INT=50
if [[ ${INT} =~ ^-?[0-9]+$ ]];then
    if [[ INT -ge MIN_VAL && INT -LE MAX_VAL ]];then
        echo "$INT is within $MIN_VAL to $MAX_VAL"
    else
        echo "$INT is out of range"
    fi
else
    echo "INT is not an integer" >&2
    exit 1
fi

例2

#!/bin/bash
# test-integer3: determine if an integer is within a
# specified range of values.
MIN_VAL=1
MAX_VAL=100
INT=50
if [[ "$INT" =~ ^-?[0-9]+$ ]]; then
    if [ ! \( $INT -gt ${MIN_VAL} -a $INT -lt ${MAX_VAL} \) ]; then
        echo "$INT is not  within $MIN_VAL to $MAX_VAL."
    else
        echo "$INT is out of range."
    fi
else
    echo "INT is not an integer." >&2
    exit 1
fi

 

三、 case命令

多分支判斷時簡化if語句,判斷類型同上。語法格式如下:

#可以使用或 |,這對於處理大小寫字符特別方便,模式的書寫類似於q|Q)
case variables in 
variables 1 | variables 2)
	command 1;;
variables 3)
	command 2;;
variables 4)
	command 3;;
*)
	default command;;
esac

使用案例

#!/bin/bash

clear
echo "
please select:
1. display disk space
2. display system information
3. display home space utilization
0. quit
"
read -p "enter selection [0-3] >"
case $REPLY in  # REPLY是提供給read命令的默認變量
0) echo "program terminated.";;
1) df -h;;
2) echo "HOSTNAME:$HOSTNAME";;
3) if [ $(id -u) -eq 0 ];then
       du -sh /home/*
   else
       du -sh $HOME
   fi;;
*) 
echo "invalid entry."
   exit 1;;
esac

 

參考

https://www.cnblogs.com/fanyunpeng/p/6412532.html

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章