天天看點

Shell 程式設計之條件語句引言一、條件測試二、 if 語句三、case 語句總結

目錄

  • 引言
  • 一、條件測試
    • 1. test 指令
    • 2. 檔案測試
    • 3. 整數值比較
    • 4. 字元串比較
    • 5. 邏輯測試
  • 二、 if 語句
    • 1. 單分支 if 語句
    • 2. 雙分支 if 語句
    • 3. 多分支 if 語句
  • 三、case 語句
    • 1. case 語句的結構
    • 2. case 語句的應用
  • 總結

引言

如果想要使 Shell 腳本程式具備一定的智能化,那麼就要知道如何區分不同的情況下該執行什麼操作,下面我來總結一下如何進行條件測試操作,通過正确使用 if 語句,使 Shell 腳本程式具有一定的判斷能力,能夠根據不同的條件來完成不同的管理任務。

一、條件測試

1. test 指令

  • Shell 環境根據指令執行後的傳回狀态值 " $? " 來判斷是否執行成功,當傳回值為0時表示成功,否則表示失敗或異常(非0值)。
  • 使用專門的測試工具 test 指令,可以對特定條件進行測試,并根據傳回值(值為0)來判斷是否成立。
  • test 指令格式如下所示
test 條件表達式
或
[ 條件表達式 ]                  #括号與表達式之間需要至少一個空格進行分隔
或
[[ 條件表達式 ]]
           

兩種方式作用完全相同,但通常後者形式更為常用,也更貼近編輯習慣。

2. 檔案測試

  • 檔案測試指的是根據給定的路徑名稱,判斷對應的是檔案還是目錄,或者判斷檔案是否可讀、可寫、可執行等。
  • 常用操作選項如下,使用時将測試對象放在操作選項之後即可
選項 說明
-d 測試是否為目錄(Directory)
-e 測試目錄或檔案是否存在(Exist)
-f 測試是否為檔案(File)
-r 測試目前使用者是否有權限讀取(Read)
-w 測試目前使用者是否有權限寫入(Write)
-x 測試目前使用者是否有權限執行(Excute)
-b 測試是否為測試檔案
-c 測試是否為字元裝置檔案
-s 測試存在且檔案大小為空
-L 測試是否為連結檔案
  • 執行條件測試操作後,通過預定義變量 “$?” 可以獲得測試指令的傳回狀态值,進而判斷該條件是否成立
[[email protected] /home]#test -d /var/log/ && echo "是目錄"
是目錄                                                 #輸出"是目錄"表示是目錄
[[email protected] /home]#test -e /var/log/ && echo "存在"
存在                                                   
[[email protected] /home]#echo $?                        #檢視指令的傳回值
0                                                     #傳回0表示條件成立
[[email protected] /home]#[ -d /home/1.txt/ ]
[[email protected] /home]#echo $?
1                                                     #傳回1表示不成立
           
  • 執行下面的操作可以判斷 /opt/目錄下是否存在名為 1.txt 的檔案,如果不存在就建立一個 1.txt 的檔案
[[email protected] /home]#[ ! -e /opt/1.txt ] && echo "yes"        #“!”表示取反的意思
yes
[[email protected] /home]#ls /opt/
rh
[[email protected] /home]#[ ! -e /opt/1.txt ] && mkdir /opt/1.txt
[[email protected] /home]#ls /opt/
1.txt  rh
           

3. 整數值比較

  • 整數值比較是指根據給定的兩個整數值來判斷第一個數與第二個數的關系,如是否大于、等于、小于第二個數。

基本格式和常用選項如下:

格式 說明
-eq 第一個數等于(Equal)第二個數
-ne 第一個數不等于(Not Equal)第二個數
-gt 第一個數大于(Greater Than)第二個數
-lt 第一個數小于( Lesser Than)第二個數
-le 第一個數小于或等于(Lesser or Equal)第二個數
-ge 第一個數大于或等于(Greater or Equal)第二個數

案例

① 執行下面的操作可以判斷目前的使用者數量,當超過3個時輸出 "使用者過多 !"

[[email protected] /home]#who | wc -l
4
[[email protected] /home]#[ $(who | wc -l) -gt 3 ] && echo "使用者過多!"
使用者過多!
           

② 若要判斷目前可用的空閑記憶體大小,當低于1800MB時輸出具體數值,可以執行下面的操作

[[email protected] /home]#FreeCC=$(free -m |grep "Mem:" | awk '{print $6}')
[[email protected] /home]#echo $?
0
[[email protected] /home]#free -m
              total        used        free      shared  buff/cache   available
Mem:           3774         735        1347           9        1692        2762
Swap:          4095           0        4095

[[email protected] /home]#[ $FreeCC -lt 1800 ] && echo ${FreeCC}MB
1692MB
           

4. 字元串比較

字元串比較通常用來檢查使用者輸入、系統環境等是否滿足條件,在提供互動式操作得 Shell 腳本中,也可以用來判斷使用者輸入得位置參數是否符合要求。

  • 常用的字元串比較操作選項如下
選項 說明
= 第一個字元串與第二個字元串相同
!= 第一個字元串與第二個字元串不相同
-z 檢查字元串是否為空,對于未定義或賦予空值的變量将視為空串

案例

如果想要判斷目前系統下的語言環境,當發現不是 “en.us” 時輸出提示資訊 “Not en.us” ,可以執行下面的操作

[[email protected] ~]#echo $LANG 
zh_CN.UTF-8
[[email protected] ~]#[ $LANG != "en.us" ] && echo "Not en.us"
Not en.us
[[email protected] ~]#[ $LANG = "en.us" ] && echo "Not en.us"          #沒有輸出結果,因為不成立
[[email protected] ~]#echo $?
1
           
[[email protected] ~]#read -p "是否覆寫該檔案(yes/no)?" ACK
是否覆寫該檔案(yes/no)?yes
[[email protected] ~]#[ $ACK = "yes" ] && echo "覆寫"                  #若輸出的是yes則輸出覆寫
覆寫   
           

5. 邏輯測試

邏輯測試指的是判斷兩個或多個條件之間的依賴關系

  • 基本格式如下
格式1  [ 表達式1 ] 操作符 [ 表達式2 ] ...
格式2  指令1 操作符 指令2 ...
           
  • 常用的邏輯測試操作如下

① -a 或 &&:邏輯與,“而且”的意思

② -o 或 || :邏輯或,“或者”的意思

③ !:邏輯否

[email protected] ~]#[ -d /etc ] && [ -r /etc ] && echo "you can open it"
you can open it                            
[[email protected] ~]#echo $?                  #兩個條件都滿足,傳回值為0
0
[[email protected] ~]#[ -f /etc ] && [ -r /etc ] && echo "you can open it"
[[email protected] ~]#echo $?                 #隻滿足一個條件,傳回值為1
1
           
[[email protected] ~]#[ -d /etc ] || [ -r /home/test.txt ] && echo "ok"
ok                                        #兩個條件隻要滿足一個即可輸出“ok”
[[email protected] ~]#ls /home/
1.txt  2.txt  3.txt  add2num.sh  gulei  ip.txt  user.sh  XYXY.sh  zhangsan

[[email protected] ~]#[ ! -f /etc && -r /etc ] && echo "ok"
-bash: [: 缺少 `]'
[[email protected] ~]#[ ! -f /etc -a -r /etc ] && echo "ok"
ok
#這裡可以看到使用"&&"時報錯,但是替換為"-a"後就可正常執行操作,是以說 Shell 腳本是可以靈活運用選項來操作的
           
[[email protected] ~]#uname -r                                  #檢視核心版本資訊
3.10.0-693.el7.x86_64
[[email protected] ~]#Mnum=$(uname -r | awk -F. '{print $1}')   #輸出版本号,以"."進行分隔
[[email protected] ~]#echo $Mnum 
3
[[email protected] ~]#Snum=$(uname -r | awk -F. '{print $2}')   #輸出版本号,以"."進行分隔
[[email protected] ~]#echo $Snum 
10
[[email protected] ~]#[ $Mnum -ge 3 ] && [ $Snum -gt 6 ] && echo "true"
true                                                         #二個條件都滿足,輸出true
           

二、 if 語句

  • 條件測試操作中,使用 “&&” 和 “||” 邏輯測試可以完成簡單的判斷并執行相應的操作,但是當我們需要執行的指令語句較多時,這種方式将使執行代碼顯得很複雜,不好了解。而使用專用的 if 條件語句,就可以更好地整理腳本結構,使得層次分明,清晰易懂。

1. 單分支 if 語句

  • if 語句的 “分支” 指的是不同測試結果所對應的執行語句(一條或多條)
  • 對于單分支的選擇結構,隻有在 “條件成立” 時才會執行相應的代碼,否則不執行任何操作
  • 單分支 if 語句的文法格式如下所示:
if條件測試操作             #可以是[ 條件表達式 ]語句,也可以是其他可執行的指令語句
then
   指令序列               #指的是一條或多條可執行的指令行,也包括嵌套使用的if語句或其他流程控制語句
fi
           
  • 單分支if語句的執行流程如下

    ① 首先判斷條件測試操作的結果,如果傳回值為0,表示條件成立,則執行 then 後面的指令序列,一直到遇見 fi 結束判斷為止,繼續執行其他腳本代碼

    ② 如果傳回值不為0,則忽略 then 後面的指令序列,直接跳至 fi 行以後執行其他腳本代碼

    Shell 程式設計之條件語句引言一、條件測試二、 if 語句三、case 語句總結
    案例
[[email protected] /home]#vim test.sh

#!/bin/bash
if ls /opt > /dev/null
then
echo "it's ok"
fi
wq儲存并退出

[[email protected] /home]#chmod +x test.sh 
[[email protected] /home]#./test.sh 
it's ok
           
[[email protected] /home]#ls /mnt/                
[[email protected] /home]#vim test1.sh  

#!/bin/bash
MOUNT_DIR="/mnt/centos7"
if [ ! -d $MOUNT_DIR ];then
mkdir -p $MOUNT_DIR
echo "$MOUNT_DIR 檔案建立成功!"
fi
wq儲存并退出
[[email protected] /home]#chmod +x test*
[[email protected] /home]#. test1.sh 
/mnt/centos7 檔案建立成功!
[[email protected] /home]#ls /mnt/
centos7
           

2. 雙分支 if 語句

  • 雙分支 if 語句是在單分支的基礎上針對 "條件不成立"的情況執行另一種操作,而不是不執行任何操作。
  • 對于雙分支的選擇結構,要針對"條件成立" "條件不成立"兩種情況分别執行不同的操作,文法格式如下
if條件測試操作
then  
      指令序列1
else  
      指令序列2
fi
           
  • 雙分支 if 語句的執行流程:

    ① 首先判斷條件測試操作的結果,如果條件成立,則執行 then 後面的指令序列1,忽略 else 及後面的命今序列2,直到遇見 fi 結束判斷

    ② 如果條件不成立,則忽略 then 及後面的指令序列1,直接跳至 else 後面的指令序列2并執行,直到遇見 fi 結束判斷

    Shell 程式設計之條件語句引言一、條件測試二、 if 語句三、case 語句總結
    案例

① 編寫一個測試網絡連通性的腳本,通過位置參數$IP 提供目标主機位址,然後根據 ping 檢測結果給出相應的提示,操作如下

[[email protected] /home]#vim test2.sh

#!/bin/bash
IP=192.168.2.9

ping -c 2 -i 0.2 -W 3 $IP &>/dev/null          #檢查目标IP是否聯通,多餘的資訊輸入到/dev/null中
if [ $? -eq 0 ]
then
        echo "$IP is up"
else
        echo "$IP is down"
fi

[[email protected] /home]#chmod +x test2.sh 
[[email protected] /home]#. test2.sh 
192.168.2.9 is up
           

[[email protected] /home]#vim test3.sh

#!/bin/bash
if [ $UID -eq 0 ]
then
        echo "目前使用者為管理者root"
else
        echo "目前使用者為普通使用者"
fi

[[email protected] /home]#bash ./test3.sh 
目前使用者為管理者root

           

3. 多分支 if 語句

  • 與單分支、雙分支 if 語句相比,多分支 if 語句的實際應用不多
  • 能夠根據多個互斥的條件分别執行不同的操作,實際上等同于嵌套使用的 if 語句
  • 文法格式如下:
if 條件測試操作1
then   指令序列1
elif 條件測試操作2
then   指令序列2
else  
       指令序列3
fi
           
  • 多分支 if 語句執行流程如下圖所示:
Shell 程式設計之條件語句引言一、條件測試二、 if 語句三、case 語句總結

案例

根據輸入的考試成績不同來區分優秀、及格、不及格三個檔,操作如下

[[email protected] /home]#vim test4.sh

#!/bin/bash
read -p "請輸入你的分數(0~100): " SCORE

if [ $SCORE -ge 85 ] && [ $SCORE -le 100 ] ;then
        echo "$SCORE 分,優秀!"
elif [ $SCORE -ge 70 ] && [ $SCORE -le 84 ] ;then
        echo ”$SCORE 分,及格!“
else
        echo "$SCORE 分,不及格!"
fi
wq儲存并退出

[[email protected] /home]#sh test4.sh 
請輸入你的分數(0~100): 99
99 分,優秀!
[[email protected] /home]#sh test4.sh 
請輸入你的分數(0~100): 75
”75 分,及格!“
[[email protected] /home]#sh test4.sh 
請輸入你的分數(0~100): 50
50 分,不及格!
           

三、case 語句

1. case 語句的結構

  • case 語句主要适用于某個變量存在多種取值,需要對其中的每一種取值分别執行不同的指令序列的情況(寫服務腳本)
  • 它和 if 語句十分相似,隻不過 if 語句是需要判斷多個不同的條件,而 case 語句隻是判斷一個變量的不同取值
  • case 分支語句的文法結構如下所示:
case 變量值 in
模式1)
	指令序列 1
	;;
模式2)
	指令序列 2
	;;
	......
*)                          # ”*“代表任意
	預設指令序列
esac
           
  • case 語句的執行流程如下:

① 首先使用"變量值"與模式1進行比較,若取得相同則執行模式1後的指令序列,直到遇到雙分号";;“後調至esac,表示結束分支

② 若與模式1不比對,則繼續與模式2進行比較,若取值相同則執行模式2後的指令序列,直到遇到雙分号”;;“後調至esac,表示結束分支

③ 後面的以此類推…

④ 若找不到任何比對的值,則執行預設模式”*)"後的指令序列,直到遇到esac後結束分支

Shell 程式設計之條件語句引言一、條件測試二、 if 語句三、case 語句總結
  • 使用case分支語句的時候,需要注意以下幾點

    ① case 行尾必須為單詞 “in”,每一個模式必須以右括号“)”結束

    ② 雙分号 “;;”辨別指令序列的結束

    ③ 模式字元串中,可以用方括号表示一個連續的範圍,比如說“[0-9]”,也可以用豎杠“|”表示或,比如“a|b”

    ④ 最後的“*)”表示預設模式,星号相當于通配符

2. case 語句的應用

[[email protected] /home]#vim test5.sh

#!/bin/bash
case $1 in
start)
/usr/bin/systemctl $1 httpd
/usr/bin/ps aux |grep httpd
echo "httpd start"
;;

stop)
/usr/bin/systemctl $1 httpd
/usr/bin/ps aux |grep httpd
echo "httpd stop"
;;

restart)
echo "正在關閉 httpd 服務......"
/usr/bin/ps aux |grep httpd
/usr/bin/systemctl $1 httpd
echo "httpd 服務正在重新啟動中......"
/usr/bin/ps aux |grep httpd
;;

status)
/usr/bin/systemctl $1 httpd
;;

*)
echo "please input start|stop|restart|status"

esac

:wq儲存并退出

           
[[email protected] /home]#yum install -y httpd
[[email protected] /home]#bash test5.sh           #除了設定的三個參數以外所有都會指向下面的輸出結果
please input start|stop|restart|status
[[email protected] /home]#bash test5.sh start     #啟動httpd服務
root      12252  0.0  0.1 221944  4972 ?        Ss   01:30   0:00 /usr/sbin/httpd -DFOREGROUND
apache    12259  0.0  0.0 224028  3092 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
root      12260  0.0  0.0 112676   960 pts/0    S+   01:30   0:00 grep httpd
apache    12261  0.0  0.0 224028  3092 ?        S    01:30   0:00 /usr/sbin/httpd -DFOREGROUND
httpd start
[[email protected] /home]#netstat -antulp |grep httpd
tcp6       0      0 :::80                   :::*                    LISTEN      12252/httpd    
[[email protected] /home]#bash test5.sh stop      #關閉httpd服務
root      12306  0.0  0.0 112676   960 pts/0    S+   01:31   0:00 grep httpd
httpd stop
[[email protected] /home]#bash test5.sh restart   #重新開機httpd服務
正在關閉 httpd 服務......
root      12344  0.0  0.1 221944  4968 ?        Ss   01:32   0:00 /usr/sbin/httpd -DFOREGROUND
apache    12347  0.0  0.0 224028  3088 ?        S    01:32   0:00 /usr/sbin/httpd -DFOREGROUND
apache    12351  0.0  0.0 224028  3088 ?        S    01:32   0:00 /usr/sbin/httpd -DFOREGROUND
root      12367  0.0  0.0 112676   956 pts/0    S+   01:34   0:00 grep httpd
httpd 服務正在重新啟動中......
root      12381  0.0  0.1 221944  4972 ?        Ss   01:34   0:00 /usr/sbin/httpd -DFOREGROUND
apache    12382  0.0  0.0 224028  3092 ?        S    01:34   0:00 /usr/sbin/httpd -DFOREGROUND
apache    12386  0.0  0.0 224028  3092 ?        S    01:34   0:00 /usr/sbin/httpd -DFOREGROUND
root      12388  0.0  0.0 112676   956 pts/0    S+   01:34   0:00 grep httpd

[[email protected] /home]#bash test5.sh status     #檢視httpd服務狀态
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
   Active: active (running) since 一 2021-09-06 01:34:15 CST; 4min 51s ago
     Docs: man:httpd(8)
           man:apachectl(8)
......
以下内容省略
           

總結

在Linux 系統中,/etc/rc.d/init.d 目錄下絕大多數的系統服務腳本使用了 case 分支語句,平時控制各種系統服務時,提供的 start、stop、restart等位置參數,正是由 case 語句結構來識别并完成相應操作的!

繼續閱讀