鍍金池/ 教程/ Linux/ shell 學(xué)習(xí)二十七天---退出狀態(tài)和 if 語句
shell 學(xué)習(xí)四十五天---xargs
shell學(xué)習(xí)第三天
shell 學(xué)習(xí)十五天---join 連接字段
shell 學(xué)習(xí)第二天
shell 學(xué)習(xí)四十三天---臨時(shí)性文件的建立與使用
shell 學(xué)習(xí)第六天---小結(jié)
shell 學(xué)習(xí)三十三天---關(guān)于重定向
shell 學(xué)習(xí)二十九天---循環(huán)
shell 學(xué)習(xí)二十四天---提取開頭或結(jié)尾數(shù)行
shell 學(xué)習(xí)第十天---sed 查找與替換
shell 學(xué)習(xí)第十一天---sed 正則的精確控制
shell 學(xué)習(xí)三十天---break,continue,shift,getopts
shell 學(xué)習(xí)---小結(jié)
shell 學(xué)習(xí)三十一天---函數(shù)問題
shell 學(xué)習(xí)第四天---華麗的 printf 輸出
shell 學(xué)習(xí)三十五天---波浪號(hào)展開與通配符
shell 學(xué)習(xí)十九天---文本塊排序
shell 學(xué)習(xí)十二天---行與字符串
shell 學(xué)習(xí)二十一天---重新格式化段落
shell 學(xué)習(xí)十八天---文本排序
shell 學(xué)習(xí)十三天---sed 案例分析
shell 學(xué)習(xí)四十一天---列出文件 ls 和 od 命令
shell 學(xué)習(xí)十七天---awk 命令
shell 學(xué)習(xí)三十六天---命令替換
shell 學(xué)習(xí)十六天---join 練習(xí)
shell 學(xué)習(xí)三十二天---read 讀取一行
shell 學(xué)習(xí)二十二天---計(jì)算行數(shù),字?jǐn)?shù)以及字符數(shù)
shell 學(xué)習(xí)小總結(jié)---本章小結(jié)
shell 學(xué)習(xí)第八天---擴(kuò)展正則表達(dá)式(ERE)
shell 學(xué)習(xí)四十二天---使用 touch 更新文件時(shí)間
shell 學(xué)習(xí)二十八天---case 語句
shell 學(xué)習(xí)三十九天---內(nèi)建命令
shell 學(xué)習(xí)第一天
shell 學(xué)習(xí)三十四天---printf 詳解
shell 學(xué)習(xí)二十六天---變量與算數(shù)
shell 學(xué)習(xí)三十八天---執(zhí)行順序和 eval
shell 學(xué)習(xí)四十四天---尋找文件
shell 學(xué)習(xí)二十五天---神器的管道符
shell 學(xué)習(xí)十四天---使用 cut 選定字段
shell 學(xué)習(xí)第五天---基本的I/O重定向
shell 學(xué)習(xí)四十天---awk 的驚人表現(xiàn)
shell 學(xué)習(xí)二十天---sort 的其他內(nèi)容以及 uniq 命令
shell 學(xué)習(xí)二十三天---打印
shell 學(xué)習(xí)第九天---分組
shell 學(xué)習(xí)四十八天---文件校驗(yàn)和匹配
shell 學(xué)習(xí)二十七天---退出狀態(tài)和 if 語句
shell 學(xué)習(xí)四十七天---文件比較 cmp,diff,patch
shell 學(xué)習(xí)第七天---基礎(chǔ)正則表達(dá)式(BRE)
shell 學(xué)習(xí)四十六天---文件系統(tǒng)的空間信息 df 和 du 命令
shell 學(xué)習(xí)三十七天---引用
shell 學(xué)習(xí)小結(jié)

shell 學(xué)習(xí)二十七天---退出狀態(tài)和 if 語句

每一條命令;不管是內(nèi)置的,shell 函數(shù),還是外部的,當(dāng)它退出時(shí),都會(huì)返回一個(gè)小的整數(shù)值給引用它的程序,這就是大家所熟知的程序的退出狀態(tài).在 shell 下執(zhí)行進(jìn)程是,有很多方式可取用程序的退出狀態(tài).
以管理來說,退出狀態(tài)為 0 表示”成功”,也就是,程序執(zhí)行完成且為遭遇到任何問題.其他任何的退出退出狀態(tài)都為失敗.內(nèi)置變量?(使用命令echo $?)查看上一條命令的退出狀態(tài).
案例:當(dāng)你輸入ls -l /dev/null時(shí).
輸出:crw-rw-rw- 1 root root 1, 3 6月 25 15:41 /dev/null
接著使用命令:echo $?
輸出為 0
接著使用命令:ls foo
輸出:ls: 無法訪問 foo: 沒有那個(gè)文件或目錄
echo $? 輸出:2
表示沒有成功的執(zhí)行.
POSIX 的結(jié)束狀態(tài)

意義

0

命令成功地退出

>0

在重定向或單詞展開期間(~,變量,命令,算數(shù)展開,以及單詞切割)失敗

1-125

命令不成功的退出.特定的退出值的含義,是由各個(gè)單獨(dú)的命令定義的.

126

命令找到了,但文件無法執(zhí)行

127

命令沒找到

>128

命令因受到信號(hào)而死亡

POSIX 留下退出狀態(tài) 128 未定義,僅要求他表示某種失敗.因?yàn)橹挥械臀坏?8 個(gè)位會(huì)返回給父進(jìn)程,所以大于255的退出狀態(tài)都會(huì)替換成該值除以 256 之后的余數(shù).
在 shell 腳本可以使用 exit 命令傳遞一個(gè)退出之給踏的調(diào)用者.只要將一個(gè)數(shù)字傳遞給它,作為一個(gè)參數(shù)即可.腳本會(huì)立即退出,并且調(diào)用者會(huì)受到該數(shù)字且作為腳本的退出值.
說白了 exit 就是退出當(dāng)前的 shell,在 shell 腳本中可以終止當(dāng)前腳本執(zhí)行.
exit
語法:
exit [exit-value]
用途:
目的是從 shell 腳本返回一個(gè)退出狀態(tài)給腳本的調(diào)用者.
主要選項(xiàng):

行為模式:
如果沒有提供,則以最后一個(gè)執(zhí)行命令的退出狀態(tài)作為默認(rèn)的退出狀態(tài).如果這就是你要的,則最好明白的在 shell 腳本里這么寫:exit $?
案例:exit
輸出為 logout,表示退出當(dāng)前 shell
案例二:腳本代碼cd $(dirname $0) || exit 1 進(jìn)入腳本所在目錄,否則退出
案例三:腳本中判斷參數(shù)數(shù)量,不匹配就打印使用方式,退出
代碼:

if [ "$#" -ne "2" ]; then  
        echo "usage: $0 <area> <hours>"  
            exit 2  
    fi  

案例四:在腳本里,退出時(shí)刪除臨時(shí)文件
代碼:trap “入門-rf tempfile;echo Bye.” exit
案例五:檢查上一行的退出碼
代碼:

EXCODE=$?  
if [ "$EXCODE" == "0" ]; then
       echo "O.K"
    fi

if-elif-else-fi 語句
if 語法:

  1. 單分支的 if 語句
    if 條件測(cè)試命令
    then
    命令序列
    fi
  2. 雙分支的 if 語句
    if 條件測(cè)試命令
    then
    命令序列 1
    else
    命令序列 2
    fi
  3. 多分支的 if 語句(elif 可以嵌套多個(gè),一般多了用 case 表達(dá))
    if 條件測(cè)試命令 1
    then
    命令序列 1
    elif 條件測(cè)試命令 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 

使用方括號(hào)作為開始與結(jié)束的關(guān)鍵字將語句組織起來.

案例 1:
提示用戶指定備份目錄的路徑,若目錄存在則顯示信息跳過,否則顯示相應(yīng)提示信息,并創(chuàng)建該目錄.
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:統(tǒng)計(jì)當(dāng)前登錄到系統(tǒng)中的用戶數(shù)量,若判斷是否超過三個(gè),若是則顯示實(shí)際數(shù)量并給出警告信息,否則列出 登錄的用戶賬戶名稱及所在終端 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 下這種情況的做法是:將驚嘆號(hào)放在管道前:

if ! grep pattern myfile > /dev/null  
then  
模式不在這里  
fi  

“如果 john 在家,且他不忙,則....”,使用邏輯 and.

if grep pattern1 myfile && grep pattern2 myfile  
then   
myfile 包含兩種模式  
fi  

相對(duì)的,||運(yùn)算符則用來測(cè)試兩個(gè)條件中是否有一個(gè)為真.:

if grep pattern1 myfile || grep pattern2 myfile  
then   
myfile 包含兩種模式之一  
fi  

邏輯 and 和 or 都是快捷運(yùn)算符,即當(dāng)判斷出整個(gè)語句塊的真?zhèn)螘r(shí),shell 會(huì)立即停止執(zhí)行命令.舉例來說,在 command1&&command2 下,如果 aommand1 失敗,則整個(gè)結(jié)果不可能為真,所以 command2 也不會(huì)被執(zhí)行;以此類推,command1||command2 指的是:如果 command1 成功,那么也沒有理由執(zhí)行 command2.
不要嘗試過度”簡(jiǎn)練”未使用&&和||來取代if語句.我們不反對(duì)簡(jiǎn)短且簡(jiǎn)單的事情,例如:
命令:who | grep root > /dev/null && echo root is login on root is login on
輸出:root is login on
分析:上面的命令實(shí)際做法是:執(zhí)行 who | grep...且如果成功,就顯示信息.而我們?cè)娺^廠商提供 shell 腳本,所使用的是這樣的結(jié)構(gòu):

```some_command &&{
one command
a decond command
and a third command
}


這個(gè)命令的意思是說將所有的語句塊放在一塊,只有在 some_command 成功時(shí)他們才被執(zhí)行.使用if可以讓他更簡(jiǎn)潔:  

if some_command
then
one command
a second command
and a third command
fi


最后在判斷語句中常用的運(yùn)算符:  
1、字符串判斷  
str1 = str2      當(dāng)兩個(gè)串有相同內(nèi)容、長(zhǎng)度時(shí)為真  
str1 != str2      當(dāng)串 str1 和 str2 不等時(shí)為真  
-n str1        當(dāng)串的長(zhǎng)度大于 0 時(shí)為真(串非空)  
-z str1        當(dāng)串的長(zhǎng)度為 0 時(shí)為真(空串)  
str1   當(dāng)串 str1 為非空時(shí)為真

2、數(shù)字的判斷  
int1 -eq int2    兩數(shù)相等為真  
int1 -ne int2    兩數(shù)不等為真  
int1 -gt int2int1 大于 int2 為真  
int1 -ge int2int1 大于等于 int2 為真  
int1 -lt int2int1 小于 int2 為真  
int1 -le int2int1 小于等于 int2 為真  
3 文件的判斷  
-r file     用戶可讀為真  
-w file     用戶可寫為真  
-x file     用戶可執(zhí)行為真  
-f file     文件為正規(guī)文件為真  
-d file     文件為目錄為真  
-c file     文件為字符特殊文件為真  
-b file     文件為塊特殊文件為真  
-s file     文件大小非 0 時(shí)為真  
-t file     當(dāng)文件描述符(默認(rèn)為 1 )指定的設(shè)備為終端時(shí)為真   
3、復(fù)雜邏輯判斷  
-a         與  
-o        或  
!        非  

test 命令  
test 命令可以處理 shell 腳本里的各類工作.它產(chǎn)生的不是一般輸出,而是可使用的退出狀態(tài).test 接受各種不同的參數(shù),可控制它要執(zhí)行哪一種測(cè)試.  

test 命令有另一種形式:[...],這種永福的作用完全與 test 命令一樣.因此,下面這兩個(gè)案例表達(dá)的意思相同  

if test “$str1”=”$str2”
then
...
fi

if [ “$str1” = “$str2” ]
then
...
fi


一樣

test 的語法:  
```test [expression]```
```[ [expression] ]```  
用途:  
為了測(cè)試 shell 腳本里的條件,通過退出狀態(tài)返回其結(jié)果.要特別注意的是:這個(gè)命令的第二種形式,方括號(hào)根據(jù)字面意義逐字的輸入,且必須與括起來的 expression 以空白隔開.  
主要選項(xiàng):  
和使用用于if的選項(xiàng)一致.  
其中  

<table>
<tbody>
<tr>
<td valign="top">
<p>選項(xiàng)</p>
</td>
<td valign="top">
<p>含義</p>
</td>
</tr>
<tr>
<td valign="top">
<p>string&nbsp; </p>
</td>
<td valign="top">
<p>如果<span style="font-family:Times New Roman">...</span><span style="font-family:宋體">則為真</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-b&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是塊設(shè)備文件</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-d&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是目錄</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-c&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是字符設(shè)備文件</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-e&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">存在</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-f&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">為一般文件</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-g&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">有設(shè)置他的</span><span style="font-family:Times New Roman">setgid</span><span style="font-family:宋體">位</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-h&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是一符號(hào)鏈接</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-L&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是一符號(hào)鏈接</span><span style="font-family:Times New Roman">(</span><span style="font-family:宋體">等同于&nbsp;</span><span style="font-family:Times New Roman">-h)</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-n&nbsp;string</p>
</td>
<td valign="top">
<p>string<span style="font-family:宋體">是非</span><span style="font-family:Times New Roman">null</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-p&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是一命名的管道</span><span style="font-family:Times New Roman">(FIGO</span><span style="font-family:宋體">文件</span><span style="font-family:Times New Roman">)</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-r&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是可讀的</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-S&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是</span><span style="font-family:Times New Roman">socket</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-s&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">不是空的</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-t&nbsp;n</p>
</td>
<td valign="top">
<p>文件描述符<span style="font-family:Times New Roman">n</span><span style="font-family:宋體">指向一終端</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-u&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">有設(shè)置它的</span><span style="font-family:Times New Roman">setuid</span><span style="font-family:宋體">位</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-w&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是可寫入的</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-x&nbsp;file</p>
</td>
<td valign="top">
<p>file<span style="font-family:宋體">是可執(zhí)行的</span><span style="font-family:Times New Roman">,</span><span style="font-family:宋體">或</span><span style="font-family:Times New Roman">file</span><span style="font-family:宋體">是可被查找的目錄</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>-z&nbsp;string</p>
</td>
<td valign="top">
<p>string<span style="font-family:宋體">為</span><span style="font-family:Times New Roman">null</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>s1=s2&nbsp;<span style="font-family:宋體">或者</span><span style="font-family:Times New Roman">s1!=s2</span></p>
</td>
<td valign="top">
<p>字符串相不相等</p>
</td>
</tr>
<tr>
<td valign="top">
<p>n1&nbsp;-eq&nbsp;n2</p>
</td>
<td valign="top">
<p>整數(shù)<span style="font-family:Times New Roman">n1</span><span style="font-family:宋體">等于</span><span style="font-family:Times New Roman">n2</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>n1&nbsp;-ne&nbsp;n2</p>
</td>
<td valign="top">
<p>整數(shù)<span style="font-family:Times New Roman">n1</span><span style="font-family:宋體">不等于</span><span style="font-family:Times New Roman">n2</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>n1&nbsp;-lt&nbsp;n2&nbsp;</p>
</td>
<td valign="top">
<p>n1<span style="font-family:宋體">小于</span><span style="font-family:Times New Roman">n2</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>n1&nbsp;-gt&nbsp;n2</p>
</td>
<td valign="top">
<p>n1<span style="font-family:宋體">大于</span><span style="font-family:Times New Roman">n2</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>n1&nbsp;-le&nbsp;n2</p>
</td>
<td valign="top">
<p>n1<span style="font-family:宋體">小于或等于</span><span style="font-family:Times New Roman">n2</span></p>
</td>
</tr>
<tr>
<td valign="top">
<p>n1&nbsp;-ge&nbsp;n2</p>
</td>
<td valign="top">
<p>n1<span style="font-family:宋體">大于或等于</span><span style="font-family:Times New Roman">n2</span></p>
</td>
</tr>
</tbody>
</table>  

案例:  
bash 代碼;  

!/bin/bash

cd /bin
if test -e ./bash //其實(shí)這里相當(dāng)于if [ -e ./bahs ]
then
echo 'the file already exist!'
else
echo 'the file not exist!'
fi



輸出結(jié)果為:the file already exist!  

另外,shell 還提供了-a(邏輯 AND ),-o(邏輯 OR),-a 的優(yōu)先級(jí)高于-o,而=與!=優(yōu)先級(jí)則高于其他的二元運(yùn)算符.  
注意:在使用-a 和-o(這兩個(gè)事 test 運(yùn)算符)與&&和||(這兩個(gè)事shell運(yùn)算符)之間有一個(gè)差異:  
```if [ -n “$str” -a -f “$file” ]``` 一個(gè)test命令,兩種條件  
```if [-n “str”] && [ -f “$file” ]``` 兩個(gè)命令,一塊接方式計(jì)算  
```if [-n “$str” && -f ”$file”]``` 語法錯(cuò)誤  
第一個(gè)案例,test 會(huì)計(jì)算兩種條件.而第二個(gè)案例,shell 執(zhí)行第一個(gè) test 命令,且只有在第一個(gè)命令是成功的情況下,才會(huì)執(zhí)行第二個(gè)命令.最后一個(gè)案例,&&為 shell 運(yùn)算符,所以它會(huì)終止第一個(gè) test 命令,然后這個(gè)命令會(huì)抱怨它找不到結(jié)束的]字符,且以失敗的值退出.即使 test 可以成功的退出,接下來的檢查還會(huì)失敗,因?yàn)?shell(最有可能)找不到一個(gè)名為-f 的命令  

## 精簡(jiǎn)表達(dá)式:  
使用命令:```[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 `]'  
注意:在[] 表達(dá)式中,常見的>,<需要加轉(zhuǎn)義字符,表示字符串大小比較,以 acill 碼位置作為比較。不直接支持<>運(yùn)算符,還有邏輯運(yùn)算符 || 和 && 它需要用-a[and] –o[or]表示。  
剛才使用的[],現(xiàn)在再來看使用[[]]  
案例:  
使用命令:[[ 2 < 3 ]]&&echo ‘OK’  
輸出 OK.  
使用命令:[[ 2 < 3 && 4 < 5 ]] && echo 'ok'  
輸出:ok  
注意:[[]] 運(yùn)算符只是[]運(yùn)算符的擴(kuò)充。能夠支持<,>符號(hào)運(yùn)算不需要轉(zhuǎn)義符,它還是以字符串比較大小。里面支持邏輯運(yùn)算符 || 和 && 
bash 的條件表達(dá)式中有三個(gè)幾乎等效的符號(hào)和命令:test,[]和[[]]。通常,大家習(xí)慣用 if [];then 這樣的形式。而[[]]的出現(xiàn),根據(jù) ABS 所說,是為了兼容><之類的運(yùn)算符。  
不考慮對(duì)低版本 bash 和對(duì) sh 的兼容的情況下,用[[]]是兼容性強(qiáng),而且性能比較快,在做條件運(yùn)算時(shí)候,可以使用該運(yùn)算符。