命令流程通常有三種 —— 順序、分支及循環,順序沒啥好說的,流程控制的重點在於分支和循環結構。
在瞭解這兩個結構之前,補充一個知識點 —— 退出狀態碼
一、 退出狀態碼
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