1. 程式人生 > >02: 數值運算 條件測試 、 if選擇結構 總結和答疑

02: 數值運算 條件測試 、 if選擇結構 總結和答疑

Top

NSD SHELL DAY02

  1. 案例1:Shell中的數值運算
  2. 案例2:條件測試操作
  3. 案例3:使用if選擇結構

1 案例1:Shell中的數值運算

1.1 問題

本案例要求熟悉Linux Shell環境的特點,主要練習以下操作:

  • 使用expr、$[ ]、let等整數運算工具:定義變數X=1234,然後計算X與78的四則運算及求模結果
  • 使用bc實現小數運算操作:以互動方式計算12.34與56.78的四則運算結果,另外再以非互動方式重複上述計算,最多顯示4位小數

1.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:整數運算工具

1)使用expr命令

乘法操作應採用 \* 轉義,避免被作為Shell萬用字元;參與運算的整數值與運算操作符之間需要以空格分開,引用變數時必須加$符號。

首先定義變數X=1234,然後分別計算與78的加減乘除和求模運算結果:

 
  1. [[email protected] ~]# X=1234                             //定義變數X
  2. [[email protected] ~]# expr $X + 78                     //加法
  3. 1312
  4. [[email protected] ~]# expr $X - 78                     //減法
  5. 1156
  6. [[email protected] ~]# expr $X \* 78                     //乘法,操作符應新增\轉義
  7. 96252
  8. [[email protected] ~]# expr $X / 78                     //除法,僅保留整除結果
  9. 15
  10. [[email protected] ~]# expr $X % 78                     //求模
  11. 64

2)使用$[]或$(())表示式

乘法操作*無需轉義,運算子兩側可以無空格;引用變數可省略 $ 符號;計算結果替換表示式本身,可結合echo命令輸出。

同樣對於變數X=1234,分別計算與78的加減乘除和求模運算結果:

 
  1. [[email protected] ~]# X=1234
  2. [[email protected] ~]# echo $[X+78]
  3. 1312
  4. [[email protected] ~]# echo $[X-78]
  5. 1156
  6. [[email protected] ~]# echo $[X*78]
  7. 96252
  8. [[email protected] ~]# echo $[X/78]
  9. 15
  10. [[email protected] ~]# echo $[X%78]
  11. 64

3)使用let命令

expr或$[]、$(())方式只進行運算,並不會改變變數的值;而let命令可以直接對變數值做運算再儲存新的值。因此變數X=1234,在執行let運算後的值會變更;另外,let運算操作並不顯示結果,但是可以結合echo命令來檢視:

 
  1. [[email protected] ~]# X=1234
  2. [[email protected] ~]# let y=X+22
  3. [[email protected] ~]# echo $y
  4. 1256
  5. [[email protected] ~]# let X++; echo $X        # X++(X=X+1)
  6. [[email protected] ~]# let X--; echo $X        # X--(X=X-1)
  7. [[email protected] ~]# let X+=78 ; echo $X        # X+=78(X=X+78)
  8. [[email protected] ~]# let X-=78 ; echo $X     # X-=78(X=X-78)
  9. [[email protected] ~]# let X*=78 ; echo $X     # X*=78(X=X*78)
  10. [[email protected] ~]# let X/=78 ; echo $X     # X/=78(X=X/78)
  11. [[email protected] ~]# let X%=78 ; echo $X     # X%=78(X=X%78)

步驟二:小數運算工具

1)bc互動式運算

先執行bc命令進入互動環境,然後再輸入需要計算的表示式。以計算小數12.34與5.678的四則運算為例,相關操作如下:

 
  1. [[email protected] ~]# bc
  2. bc 1.06.95
  3. Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
  4. This is free software with ABSOLUTELY NO WARRANTY.
  5. For details type `warranty'.
  6. 12.34+56.78                                        //加法
  7. 69.12
  8. 12.34-56.78                                        //減法
  9. -44.44
  10. 12.34*56.78                                        //乘法
  11. 700.66
  12. 12.34/56.78                                        //除法
  13. 0
  14. quit                                             //退出互動計算器
  15. [[email protected] ~]#

2)bc非互動式運算

將需要運算的表示式通過管道操作交給bc運算。注意,小數位的長度可採用scale=N限制,除此以外也受參與運算的數值的小數位影響。以計算小數12.34與5.678的四則運算為例,相關操作如下:

 
  1. [[email protected] ~]# echo 'scale=4;12.34+5.678' | bc
  2. 18.018
  3. [[email protected] ~]# echo 'scale=4;12.34*5.678' | bc
  4. 70.0665
  5. [[email protected] ~]# echo 'scale=4;12.34/5.678' | bc
  6. 2.1733

2 案例2:條件測試操作

2.1 問題

本案例要求參考PPT上的示例,分別練習以下條件測試操作:

  • 字串匹配
  • 比較整數值的大小
  • 識別檔案/目錄的狀態
  • 多個條件/操作的邏輯組合

2.2 步驟

實現此案例需要按照如下步驟進行。

步驟一:條件測試的基本用法

1)語法格式

使用“test 表示式”或者[ 表示式 ]都可以,表示式兩邊至少要留一個空格。

條件測試操作本身不顯示出任何資訊。測試的條件是否成立主要體現在命令執行後的返回狀態(即 $?),所以可以在測試後檢視變數$?的值來做出判斷,或者結合&&、||等邏輯操作顯示出結果(或作其他操作) 。

步驟二:字串測試

1)== 比較兩個字串是否相同

檢查當前使用者是否為root。

當root使用者執行時:

 
  1. [[email protected] ~]# [ $USER == "root" ]         //測試
  2. [[email protected] ~]# echo $?                    //檢視結果0為對,非0為錯

當普通使用者執行時:

 
  1. [[email protected] ~]$ [ $USER == "root" ]
  2. [[email protected] ~]$ echo $? //檢視結果0為對,非0為錯

2)!= 比較兩個字串是否不相同

當普通使用者執行時:

 
  1. [[email protected] ~]$ [ $USER != "root" ]

當root使用者執行時:

 
  1. [[email protected] ~]# [ $USER != "root" ]

3)一行執行多條命令的情況

 
  1. # A && B                     //僅當A命令執行成功,才執行B命令
  2. # A || B                        //僅當A命令執行失敗,才執行B命令
  3. # A ; B                        //執行A命令後執行B命令,兩者沒有邏輯關係
  4. # A && B || C //思考?

4) -z 檢查變數的值是否未設定(空值)

 
  1. [[email protected] ~]# var1="nb" ; var2=""
  2. [[email protected] ~]# [ -z "$var1" ] && echo "空值" || echo "非空值"
  3. 非空值
  4. [[email protected] ~]# [ -z $var2 ] && echo "空值" || echo "非空值"
  5. 空值                                     //變數var2已設定,但無任何值,視為空
  6. [[email protected] ~]# [ ! -z $var1 ]                //測試var1是否為非空

還有一個-n可以測試變數是否不為空(相當於! -z)。

步驟三:整數值比較

參與比較的必須是整數(可以呼叫變數),比較非整數值時會出錯:

 
  1. [[email protected] ~]# A=20.4
  2. [[email protected] ~]# [ $A -gt 10 ]                 //不支援小數比較
  3. -bash: [: 20.4: integer expression expected

1)-eq 比較兩個數是否相等。

 
  1. [[email protected] ~]# X=20                         //定義一個測試變數
  2. [[email protected] ~]# [ $X -eq 20 ] && echo "相等" || echo "不相等"
  3. 相等
  4. [[email protected] ~]# [ $X -eq 30 ] && echo "相等" || echo "不相等"
  5. 不相等

2)-ne 比較兩個數是否不相等。

 
  1. [[email protected] ~]# X=20                         //定義一個測試變數
  2. [[email protected] ~]# [ $X -ne 20 ] && echo "不等於" || echo "等於"
  3. 等於
  4. [[email protected] ~]# [ $X -ne 30 ] && echo "不等於" || echo "等於"
  5. 不等於

3)-gt 比較前面的整數是否大於後面的整數。

 
  1. [[email protected] ~]# X=20                         //定義一個測試變數
  2. [[email protected] ~]# [ $X -gt 10 ] && echo "大於" || echo "否"
  3. 大於
  4. [[email protected] ~]# [ $X -gt 20 ] && echo "大於" || echo "否"
  5. [[email protected] ~]# [ $X -gt 30 ] && echo "大於" || echo "否"

4)-ge 比較前面的整數是否大於或等於後面的整數。

 
  1. [[email protected] ~]# X=20                         //定義一個測試變數
  2. [[email protected] ~]# [ $X -ge 10 ] && echo "大於或等於" || echo "否"
  3. 大於或等於
  4. [[email protected] ~]# [ $X -ge 20 ] && echo "大於或等於" || echo "否"
  5. 大於或等於
  6. [[email protected] ~]# [ $X -ge 30 ] && echo "大於或等於" || echo "否"

5)-lt 比較前面的整數是否小於後面的整數。

 
  1. [[email protected] ~]# X=20                         //定義一個測試變數
  2. [[email protected] ~]# [ $X -lt 10 ] && echo "小於" || echo "否"
  3. [[email protected] ~]# [ $X -lt 20 ] && echo "小於" || echo "否"
  4. [[email protected] ~]# [ $X -lt 30 ] && echo "小於" || echo "否"
  5. 小於

6)-le 比較前面的整數是否小於或等於後面的整數。

 
  1. [[email protected] ~]# X=20                         //定義一個測試變數
  2. [[email protected] ~]# [ $X -le 10 ] && echo "小於或等於" || echo "否"
  3. [[email protected] ~]# [ $X -le 20 ] && echo "小於或等於" || echo "否"
  4. 小於或等於
  5. [[email protected] ~]# [ $X -le 30 ] && echo "小於或等於" || echo "否"
  6. 小於或等於

7)提取當前登入的使用者數,比較是否大於等於3。

 
  1. [[email protected] ~]# who | wc -l                                 //確認已登入的使用者數
  2. 2
  3. [[email protected] ~]# N=$(who | wc -l)                             //賦值給變數N
  4. [[email protected] ~]# [ $N -ge 3 ] && echo "超過了" || echo "沒超過"
  5. 沒超過

上述賦值給變數N及與3比較的操作,可以簡化為如下形式:

 
  1. [[email protected] ~]# [ $(who | wc -l) -ge 3 ] && echo "超過了" || echo "沒超過"
  2. 沒超過

步驟四:識別檔案/目錄的狀態

1)-e 判斷物件是否存在(不管是目錄還是檔案)

 
  1. [[email protected] ~]# [ -e "/usr/" ] && echo "存在" || echo "不存在"
  2. 存在
  3. [[email protected] ~]# [ -e "/etc/fstab" ] && echo "存在" || echo "不存在"
  4. 存在
  5. [[email protected] ~]# [ -e "/home/nooby" ] && echo "存在" || echo "不存在"
  6. 不存在

2)-d 判斷物件是否為目錄(存在且是目錄)

 
  1. [[email protected] ~]# [ -d "/usr/" ] && echo "是目錄" || echo "不是目錄"
  2. 是目錄
  3. [[email protected] ~]# [ -d "/etc/fstab" ] && echo "是目錄" || echo "不是目錄"
  4. 不是目錄
  5. [[email protected] ~]# [ -d "/home/nooby" ] && echo "是目錄" || echo "不是目錄"
  6. 不是目錄

3)-f 判斷物件是否為檔案(存在且是檔案)

 
  1. [[email protected] ~]# [ -f "/usr/" ] && echo "是檔案" || echo "不是檔案"
  2. 不是檔案
  3. [[email protected] ~]# [ -f "/etc/fstab" ] && echo "是檔案" || echo "不是檔案"
  4. 是檔案
  5. [[email protected] ~]# [ -f "/home/nooby" ] && echo "是檔案" || echo "不是檔案"
  6. 不是檔案

4)-r 判斷物件是否可讀

此測試對root使用者無效,無論檔案是否設定r許可權,root都可讀:

 
  1. [[email protected] ~]# cp /etc/hosts /tmp/test.txt         //複製一個檔案做測試
  2. [[email protected] ~]# chmod -r /tmp/test.txt             //去掉所有的r許可權
  3. [[email protected] ~]# [ -r "/tmp/test.txt" ] && echo "可讀" || echo "不可讀"
  4. 可讀                                             //root測試結果仍然可讀

切換為普通使用者,再執行相同的測試,結果變為“不可讀”:

 
  1. [[email protected] ~]$ [ -r "/tmp/test.txt" ] && echo "可讀" || echo "不可讀"
  2. 不可讀

5)-w 判斷物件是否可寫

此測試同樣對root使用者無效,無論檔案是否設定w許可權,root都可寫:

 
  1. [[email protected] ~]# chmod -w /tmp/test.txt             //去掉所有的w許可權
  2. [[email protected] ~]# ls -l /tmp/test.txt             //確認設定結果
  3. ---------- 1 root root 33139 12-11 10:43 /tmp/test.txt
  4. [[email protected] ~]# [ -w "/tmp/test.txt" ] && echo "可寫" || echo "不可寫"
  5. 可寫

切換為普通使用者,可以正常使用-w測試:

 
  1. [[email protected] ~]$ ls -l /tmp/test.txt
  2. ---------- 1 root root 33139 12-11 10:52 /tmp/test.txt
  3. [[email protected] ~]$ [ -w "/tmp/test.txt" ] && echo "可寫" || echo "不可寫"
  4. 不可寫

6)-x 判斷物件是否具有可執行許可權

這個取決於檔案本身、檔案系統級的控制,root或普通使用者都適用:

 
  1. [[email protected] ~]# chmod 644 /tmp/test.txt         //重設許可權,無x
  2. [[email protected] ~]# ls -l /tmp/test.txt             //確認設定結果
  3. -rw-r--r-- 1 root root 33139 12-11 10:52 /tmp/test.txt
  4. [[email protected] ~]# [ -x "/tmp/test.txt" ] && echo "可執行" || echo "不可執行"
  5. 不可執行
  6. [[email protected] ~]# chmod +x /tmp/test.txt         //新增x許可權
  7. [[email protected] ~]# [ -x "/tmp/test.txt" ] && echo "可執行" || echo "不可執行"
  8. 可執行

步驟五:多個條件/操作的邏輯組合

1)&&,邏輯與

給定條件必須都成立,整個測試結果才為真。

檢查變數X的值是否大於10,且小於30:

 
  1. [[email protected] ~]# X=20                     //設定X變數的值為20
  2. [[email protected] ~]# [ $X -gt 10 ] && [ $X -lt 30 ] && echo "YES"
  3. YES

2)||,邏輯或

只要其中一個條件成立,則整個測試結果為真。

只要/tmp/、/var/spool/目錄中有一個可寫,則條件成立:

 
  1. [[email protected] ~]# [ -w "/tmp/" ] || [ -w "/var/spool/" ] && echo "OK"
  2. OK

3 案例3:使用if選擇結構

3.1 問題

本案例要求編寫3個Shell指令碼,分別實現以下目標:

  • 檢測/media/cdrom目錄,若不存在則建立
  • 檢測並判斷指定的主機是否可ping通
  • 從鍵盤讀取一個論壇積分,判斷論壇使用者等級,等級分類如下:

大於等於90 神功絕世

大於等於80,小於90 登峰造極

大於等於70,小於80 爐火純青

大於等於60,小於70 略有小成

小於60 初學乍練

3.2 方案

if單分支的語法組成:

 
  1. if 條件測試
  2. then
  3. 命令序列
  4. fi

if雙分支的語法組成:

 
  1. if 條件測試
  2. then
  3. 命令序列1
  4. else
  5. 命令序列2
  6. fi

if多分支的語法組成:

 
  1. if 條件測試1 ;then
  2. 命令序列1
  3. elif 條件測試2 ;then
  4. 命令序列2
  5. else
  6. 命令序列n
  7. fi

3.3 步驟

實現此案例需要按照如下步驟進行。

步驟一:檢測/media/cdrom目錄,若不存在則建立

1)編寫指令碼如下:

 
  1. [[email protected] ~]# vim mountdir.sh
  2. #!/bin/bash
  3. dir="/media/cdrom/"
  4. if [ ! -d $dir ]
  5. then
  6. mkdir -p $dir
  7. fi
  8.  
  9. [[email protected] ~]# chmod +x mountdir.sh                 //新增可執行許可權

2)測試、驗證指令碼功能

 
  1. [[email protected] ~]# ls -ld /media/cdrom                 //本來沒有/media/cdrom目錄
  2. ls: /media/cdrom: 沒有那個檔案或目錄
  3. [[email protected] ~]# ./mountdir.sh                         //執行指令碼
  4. [[email protected] ~]# ls -ld /media/cdrom                 //再檢查已經有了
  5. drwxr-xr-x 2 root root 4096 12-11 15:16 /media/cdrom

有了/media/cdrom資料夾以後,再次執行上述指令碼,實際上不做任何有效操作:

 
  1. [[email protected] ~]# ./mountdir.sh

步驟二:檢測並判斷指定的主機是否可ping通

1)分析任務需求

使用ping命令檢測目標主機時,人工可直接判斷反饋結果,而指令碼卻不方便。但是當ping測試成功時,執行狀態$?的值為0;而ping測試失敗時,$?的值不為0。因此在Shell指令碼中可以利用這一點來判斷ping目標主機的成敗。

為了節省ping測試時間,可以只發送3個測試包(-c 3)、縮短髮送測試包的間隔秒數(-i 0.2)、等待反饋的超時秒數(-W 1)。比如,檢查可ping通的主機:

 
  1. [[email protected] ~]# ping -c 3 -i 0.2 -W 1 192.168.4.5
  2. PING 192.168.4.5 (192.168.4.5) 56(84) bytes of data.
  3. 64 bytes from 192.168.4.5: icmp_seq=1 ttl=64 time=0.131 ms
  4. 64 bytes from 192.168.4.5: icmp_seq=2 ttl=64 time=0.076 ms
  5. 64 bytes from 192.168.4.5: icmp_seq=3 ttl=64 time=0.073 ms
  6.  
  7. --- 192.168.4.5 ping statistics ---
  8. 3 packets transmitted, 3 received, 0% packet loss, time 402ms
  9. rtt min/avg/max/mdev = 0.073/0.093/0.131/0.027 ms
  10.  
  11. [[email protected] ~]# echo $?                                 //執行狀態表示成功
  12. 0

2)指令碼編寫參考如下:

 
  1. [[email protected] ~]# vim pinghost.sh
  2. #!/bin/bash
  3. ping -c 3 -i 0.2 -W 1 $1 &> /dev/null
  4. if [ $? -eq 0 ] ; then
  5. echo "Host $1 is up."
  6. else
  7. echo "Host $1 is down."
  8. fi
  9.  
  10. [[email protected] ~]# chmod +x pinghost.sh

3)測試、驗證指令碼功能

 
  1. [[email protected] ~]# ./pinghost.sh 192.168.4.5
  2. Host 192.168.4.5 is up.
  3. [[email protected] ~]# ./pinghost.sh 192.168.4.50
  4. Host 192.168.4.50 is down.

步驟三:從鍵盤讀取一個論壇積分,判斷論壇使用者等級

1)指令碼編寫參考如下:

大於等於90 神功絕世

大於等於80,小於90 登峰造極

大於等於70,小於80 爐火純青

大於等於60,小於70 略有小成

小於60 初學乍練

 
  1. [[email protected] ~]# vim grade.sh
  2. #!/bin/bash
  3. read -p "請輸入積分(0-100):" JF
  4. if [ $JF -ge 90 ] ; then
  5. echo "$JF 分,神功絕世"
  6. elif [ $JF -ge 80 ] ; then
  7. echo "$JF 分,登峰造極"
  8. elif [ $JF -ge 70 ] ; then
  9. echo "$JF 分,爐火純青"
  10. elif [ $JF -ge 60 ] ; then
  11. echo "$JF 分,略有小成"
  12. else
  13. echo "$JF 分,初學乍練"
  14. fi
  15.  
  16. [[email protected] ~]# chmod +x grade.sh

3)測試、驗證指令碼

 
  1. [[email protected] ~]# ./grade.sh
  2. 請輸入積分(0-100):74
  3. 74 分,爐火純青
  4. [[email protected] ~]# ./grade.sh
  5. 請輸入分數(0-100):68
  6. 68 分,略有小成
  7. [[email protected] ~]# ./grade.sh
  8. 請輸入分數(0-100):87
  9. 87 分,登峰造極