shell學習二十七天----退出狀態和if語句
退出狀態
每一條命令;不管是內建的,shell函式,還是外部的,當它退出時,都會返回一個小的整數值給引用它的程式,這就是大家所熟知的程式的退出狀態.在shell下執行程序是,有很多方式可取用程式的退出狀態.
以管理來說,退出狀態為0表示”成功”,也就是,程式執行完成且為遭遇到任何問題.其他任何的退出退出狀態都為失敗.內建變數?(使用命令echo $?)檢視上一條命令的退出狀態.
案例:當你輸入ls -l /dev/null時.
輸出:crw-rw-rw- 1 root root 1, 3 6月 25 15:41 /dev/null
接著使用命令:echo $?
輸出為0
接著使用命令:ls foo
輸出:ls:
echo $?
輸出:2
表示沒有成功的執行.
POSIX的結束狀態
值 |
意義 |
0 |
命令成功地退出 |
>0 |
在重定向或單詞展開期間(~,變數,命令,算數展開,以及單詞切割)失敗 |
1-125 |
命令不成功的退出.特定的退出值的含義,是由各個單獨的命令定義的. |
126 |
命令找到了,但檔案無法執行 |
127 |
命令沒找到 |
>128 |
命令因受到訊號而死亡 |
POSIX留下退出狀態128未定義,僅要求他表示某種失敗.因為只有低位的8個位會返回給父程序,所以大於255的退出狀態都會替換成該值除以256之後的餘數
在shell指令碼可以使用exit命令傳遞一個退出之給踏的呼叫者.只要將一個數字傳遞給它,作為一個引數即可.指令碼會立即退出,並且呼叫者會受到該數字且作為指令碼的退出值.
說白了exit就是退出當前的shell,在shell指令碼中可以終止當前指令碼執行.
exit
語法:
exit [exit-value]
用途:
目的是從shell指令碼返回一個退出狀態給指令碼的呼叫者.
主要選項:
無
行為模式:
如果沒有提供,則以最後一個執行命令的退出狀態作為預設的退出狀態.如果這就是你要的,則最好明白的在shell腳本里這麼寫:exit $?
案例:exit
輸出為logout,表示退出當前shell
案例二:指令碼程式碼cd $(dirname $0) || exit 1
進入指令碼所在目錄,否則退出
案例三:指令碼中判斷引數數量,不匹配就列印使用方式,退出
程式碼:
if [ "$#" -ne "2" ]; then
echo "usage: $0 <area> <hours>"
exit 2
fi
案例四:在腳本里,退出時刪除臨時檔案
程式碼:trap “入門-rf tempfile;echo Bye.” exit
案例五:檢查上一行的退出碼
程式碼:
EXCODE=$?
if [ "$EXCODE" == "0" ]; then
echo "O.K"
fi
if-elif-else-fi語句
if語法:
1、單分支的if語句
if 條件測試命令
then
命令序列
fi
2、雙分支的if語句
if 條件測試命令
then
命令序列1
else
命令序列2
fi
3、多分支的if語句(elif 可以巢狀多個,一般多了用case表達)
if 條件測試命令1
then
命令序列1
elif 條件測試命令2
then
命令序列2
.........
else
命令序列n
fi
if pipeline
[pipeline...]
then
statement-if-true-1
elif pipeline
[pipeline...]
then
statement-iftrue2
else
statement-if-all-else-fails
if
使用方括號作為開始與結束的關鍵字將語句組織起來.
案例1:
提示使用者指定備份目錄的路徑,若目錄存在則顯示資訊跳過,否則顯示相應提示資訊,並建立該目錄.
bash程式碼:
#!/bin/bash
read -p "what is your backup directoy : " BakDir
if [ -d $BakDir ];then
echo "$BakDir alerdy exist"
else
echo "$BakDir is not exist,will make it"
mkdir $BakDir
fi
案例2:統計當前登入到系統中的使用者數量,若判斷是否超過三個,若是則顯示實際數量並給出警告資訊,否則列出
登入的使用者賬戶名稱及所在終端
bash程式碼:
UserNum='who | wc -l'
if [ $UserNum -gt 3 ];
then
echo "Alert, too many login users ( Total: $UserNum)."
else
echo "Login Users:"
who | awk '{print $1,$2}'
fi
注意:
1、if 與[ 之間必須有空格
2、[ ]與判斷條件之間也必須有空格
3、]與; 之間不能有空格
邏輯的not,and與or
“如果john不在家,則...” ,在shell下這種情況的做法是:將驚歎號放在管道前:
if ! grep pattern myfile > /dev/null
then
模式不在這裡
fi
“如果john在家,且他不忙,則....”,使用邏輯and.
if grep pattern1 myfile && grep pattern2 myfile
then
myfile包含兩種模式
fi
相對的,||運算子則用來測試兩個條件中是否有一個為真.:
if grep pattern1 myfile || grep pattern2 myfile
then
myfile包含兩種模式之一
fi
邏輯and和or都是快捷運算子,即當判斷出整個語句塊的真偽時,shell會立即停止執行命令.舉例來說,在command1&&command2下,如果aommand1失敗,則整個結果不可能為真,所以command2也不會被執行;以此類推,command1||command2指的是:如果command1成功,那麼也沒有理由執行command2.
不要嘗試過度”簡練”未使用&&和||來取代if語句.我們不反對簡短且簡單的事情,例如:
命令:who | grep root > /dev/null && echo root is login on root is login on
輸出:root is login on
分析:上面的命令實際做法是:執行who | grep...且如果成功,就顯示資訊.而我們曾見過廠商提供shell指令碼,所使用的是這樣的結構:
some_command &&{
one command
a decond command
and a third command
}
這個命令的意思是說將所有的語句塊放在一塊,只有在some_command成功時他們才被執行.使用if可以讓他更簡潔:
if some_command
then
one command
a second command
and a third command
fi
最後在判斷語句中常用的運算子:
1、字串判斷
str1 = str2 當兩個串有相同內容、長度時為真
str1 != str2 當串str1和str2不等時為真
-n str1 當串的長度大於0時為真(串非空)
-z str1 當串的長度為0時為真(空串)
str1當串str1為非空時為真
2、數字的判斷
int1 -eq int2 兩數相等為真
int1 -ne int2 兩數不等為真
int1 -gt int2int1大於int2為真
int1 -ge int2int1大於等於int2為真
int1 -lt int2int1小於int2為真
int1 -le int2int1小於等於int2為真
3 檔案的判斷
-r file 使用者可讀為真
-w file 使用者可寫為真
-x file 使用者可執行為真
-f file 檔案為正規檔案為真
-d file 檔案為目錄為真
-c file 檔案為字元特殊檔案為真
-b file 檔案為塊特殊檔案為真
-s file 檔案大小非0時為真
-t file 當檔案描述符(預設為1)指定的裝置為終端時為真
3、複雜邏輯判斷
-a 與
-o 或
! 非
test命令
test命令可以處理shell腳本里的各類工作.它產生的不是一般輸出,而是可使用的退出狀態.test接受各種不同的引數,可控制它要執行哪一種測試.
test命令有另一種形式:[...],這種永福的作用完全與test命令一樣.因此,下面這兩個案例表達的意思相同
if test “$str1”=”$str2”
then
...
fi
和
if [ “$str1” = “$str2” ]
then
...
fi
一樣
test的語法:
test [expression]
[ [expression] ]
用途:
為了測試shell腳本里的條件,通過退出狀態返回其結果.要特別注意的是:這個命令的第二種形式,方括號根據字面意義逐字的輸入,且必須與括起來的expression以空白隔開.
主要選項:
和使用用於if的選項一致.
其中
選項 |
含義 |
string |
如果...則為真 |
-b file |
file是塊裝置檔案 |
-d file |
file是目錄 |
-c file |
file是字元裝置檔案 |
-e file |
file存在 |
-f file |
file為一般檔案 |
-g file |
file有設定他的setgid位 |
-h file |
file是一符號連結 |
-L file |
file是一符號連結(等同於 -h) |
-n string |
string是非null |
-p file |
file是一命名的管道(FIGO檔案) |
-r file |
file是可讀的 |
-S file |
file是socket |
-s file |
file不是空的 |
-t n |
檔案描述符n指向一終端 |
-u file |
file有設定它的setuid位 |
-w file |
file是可寫入的 |
-x file |
file是可執行的,或file是可被查詢的目錄 |
-z string |
string為null |
s1=s2 或者s1!=s2 |
字串相不相等 |
n1 -eq n2 |
整數n1等於n2 |
n1 -ne n2 |
整數n1不等於n2 |
n1 -lt n2 |
n1小於n2 |
n1 -gt n2 |
n1大於n2 |
n1 -le n2 |
n1小於或等於n2 |
n1 -ge n2 |
n1大於或等於n2 |
案例:
bash程式碼;
#!/bin/bash
cd /bin
if test -e ./bash //其實這裡相當於if [ -e ./bahs ]
then
echo 'the file already exist!'
else
echo 'the file not exist!'
fi
輸出結果為:the file already exist!
另外,shell還提供了-a(邏輯AND),-o(邏輯OR),-a的優先順序高於-o,而=與!=優先順序則高於其他的二元運算子.
注意:在使用-a和-o(這兩個事test運算子)與&&和||(這兩個事shell運算子)之間有一個差異:
if [ -n “$str” -a -f “$file” ] 一個test命令,兩種條件
if [-n “str”] && [ -f “$file” ] 兩個命令,一塊接方式計算
if [-n “$str” && -f ”$file”] 語法錯誤
第一個案例,test會計算兩種條件.而第二個案例,shell執行第一個test命令,且只有在第一個命令是成功的情況下,才會執行第二個命令.最後一個案例,&&為shell運算子,所以它會終止第一個test命令,然後這個命令會抱怨它找不到結束的]字元,且以失敗的值退出.即使test可以成功的退出,接下來的檢查還會失敗,因為shell(最有可能)找不到一個名為-f的命令
精簡表示式:
使用命令:[1 eq1 ] &&echo’OK’
輸出:ok
使用命令:[ 2 < 1 ] &&echo ‘OK’
輸出:-bash: 1: No such file or directory
使用命令:[ 2 \< 1 ] &&echo ‘OK’這樣就可以了
使用命令:[ 2 -gt 1 -a 3 -lt 4 ]&&echo 'Ok'
輸出:Ok
使用命令:[ 2 -gt 1 && 3 -lt 4 ]&&echo 'Ok'
輸出:-bash: [: missing `]'
注意:在[] 表示式中,常見的>,<需要加轉義字元,表示字串大小比較,以acill碼位置作為比較。不直接支援<>運算子,還有邏輯運算子 || 和 && 它需要用-a[and] –o[or]表示。
剛才使用的[],現在再來看使用[[]]
案例:
使用命令:[[ 2 < 3 ]]&&echo ‘OK’
輸出OK.
使用命令:[[ 2 < 3 && 4 < 5 ]] && echo 'ok'
輸出:ok
注意:[[]] 運算子只是[]運算子的擴充。能夠支援<,>符號運算不需要轉義符,它還是以字串比較大小。裡面支援邏輯運算子 || 和 &&
bash 的條件表示式中有三個幾乎等效的符號和命令:test,[]和[[]]。通常,大家習慣用if [];then這樣的形式。而[[]]的出現,根據ABS所說,是為了相容><之類的運算子。
不考慮對低版本bash和對sh的相容的情況下,用[[]]是相容性強,而且效能比較快,在做條件運算時候,可以使用該運算子。