Bash腳本編程學習筆記06:條件結構體

来源:https://www.cnblogs.com/alongdidi/archive/2020/01/15/bash_conditional_construct.html
-Advertisement-
Play Games

簡介 在bash腳本編程中,條件結構體使用if語句和case語句兩種句式。 if語句 單分支if語句 if TEST; then CMD fi TEST:條件判斷,多數情況下可使用test命令來實現,返回值為0的話則執行CMD,否則就離開該條件結構體,腳本繼續往下執行。 [root@c7-serve ...


簡介

在bash腳本編程中,條件結構體使用if語句和case語句兩種句式。

if語句

單分支if語句

if TEST; then
    CMD
fi

TEST:條件判斷,多數情況下可使用test命令來實現,返回值為0的話則執行CMD,否則就離開該條件結構體,腳本繼續往下執行。

[root@c7-server ~]# cat test.sh
#!/bin/bash
if id zwl &> /dev/null; then
    echo "User zwl exists."
fi
[root@c7-server ~]# bash test.sh 
User zwl exists.

雙分支if語句

if TEST; then
  
CMD-TRUE else
  
CMD-FALSE fi

為真執行CMD-TRUE,為假執行CMD-FALSE。

[root@c7-server ~]# cat test.sh
#!/bin/bash
read -p "Pleas input a user name:" name
if id $name &> /dev/null; then
    echo "User $name exists."
else
    echo "User $name doesn't exists."
fi
[root@c7-server ~]# bash test.sh 
Pleas input a user name:zwl
User zwl exists.
[root@c7-server ~]# bash test.sh 
Pleas input a user name:alongdidi
User alongdidi doesn't exists.

多分支if語句

if TEST1; then
    CMD1
elif TEST2; then
    CMD2
elif TEST3; then
    CMD3
...
else
    CMD-LAST
fi

當TEST1為真時執行CMD1,否則判斷TEST2;當TEST2為真時執行CMD2,否則判斷TEST3;以此類推,都不符合條件的話則執行CMD-LAST。

判斷文件類型的示例。

#!/bin/bash
read -p "Please input only a absolute file path:" file

if [ -z $file ]; then
    echo "You must input something."
    exit 2
fi

if [ ! -e $file ]; then
    echo "No such file $file"
elif [ -d $file ]; then
    echo "File $file is a directory."
elif [ -L $file ]; then
    echo "File $file is a symbolic."
elif [ -b $file ]; then
    echo "File $file is a block special file."
elif [ -c $file ]; then
    echo "File $file is a character special file."
elif [ -S $file ]; then
    echo "File $file is a socket file."
elif [ -f $file ]; then
    echo "File $file is a regular file."
else
    echo "File is unrecognized."
fi

執行示例。

[root@c7-server ~]# bash test.sh 
Please input only a absolute file path:
You must input something.
[root@c7-server ~]# bash test.sh 
Please input only a absolute file path:passwd
No such file passwd
[root@c7-server ~]# bash test.sh 
Please input only a absolute file path:/etc/passwd        
File /etc/passwd is a regular file
[root@c7-server ~]# bash test.sh 
Please input only a absolute file path:/root/
File /root/ is a directory.
[root@c7-server ~]# bash test.sh 
Please input only a absolute file path:/etc/rc.local
File /etc/rc.local is a symbolic.

字元鏈接文件也可以被認為是普通文件(regular),因此建議將普通文件的判定放置在較靠後的位置。

註意:if語句是可以嵌套的。

[root@c7-server ~]# cat test.sh
#!/bin/bash
if [ -e /dev/sda ]; then
    if [ -b /dev/sda ]; then
        echo "It's a block file."
    fi
fi
[root@c7-server ~]# bash test.sh
It's a block file.

其他示例

編寫一個腳本,僅可接收一個參數,此參數應是一個用戶名稱。判斷該用戶名是否存在,若存在則輸出用戶的信息,否則就創建該用戶並設置預設密碼(password)。

#!/bin/bash

if [ $# -ne 1 ];then
    echo "You must input just one argument!"
    exit 2
fi

if id $1 &> /dev/null; then
    id $1
else
    useradd $1
    echo "password" | passwd --stdin $1 &> /dev/null
fi

編寫一個腳本,接收兩個數值類參數,並輸出其中較大的那個。

#!/bin/bash

if [ $# -ne 2 ]; then
    echo "Please input exact two number arguments."
    exit 1
fi

if [ $1 -eq $2 ]; then
    echo "Number $1 and $2 are equal."
elif [ $1 -gt $2 ]; then
    echo "The greater is $1."
else
    echo "The greater is $2."
fi

編寫一個腳本,接收一個用戶名作為參數,並判斷其奇偶性。

[root@c7-server ~]# cat even_odd_if.sh 
#!/bin/bash

if [ $# -ne 1 ]; then
    echo "You must input just one argument."
    exit 1
fi

var=$[$(id -u $1)%2]
if [ $var -eq 0 ]; then
    echo "The UID of $1 is even."
else
    echo "The UID of $1 is odd."
fi

編寫一個腳本,接收兩個文件名作為參數,返迴文件的行數以及判斷哪個文件的行數比較多。

#!/bin/bash

if [ $# -ne 2 ]; then
    echo "You must input exat 2 arguments."
    exit 1
fi

if [ ! -e $1 -o ! -e $2 ]; then
    echo "File $1 or/and $2 doesn't/don't exist[s]."
    exit 2
fi

line1=$(wc -l $1 | cut -d " " -f 1)
line2=$(wc -l $2 | cut -d " " -f 1)
echo "The lines of $1 is $line1"
echo "The lines of $2 is $line2"

if [ $line1 -gt $line2 ]; then
    echo "$1 has more lines."
elif [ $line1 -lt $line2 ]; then
    echo "$2 has more lines."
else
    echo "They have same lines."
fi

編寫一個腳本,傳遞一個用戶名作為參數給腳本,判斷用戶的類型。

UID=0:管理員

UID=1~999:系統用戶

UID=1000+:普通用戶

#!/bin/bash

if [ $# -ne 1 ]; then
    echo "You must input exact one argument."
    exit 1
fi

if ! id $1 &> /dev/null; then
    echo "You must input an existed username."
    exit 2
fi

userId=$(id -u $1)
if [ $userId -eq 0 ]; then
    echo "$1 is a admin user."
elif [ $userId -lt 1000 ]; then
    echo "$1 is a system user."
else
    echo "$1 is a normal user."
fi

編寫一個腳本,展示一個菜單供用戶選擇,菜單告知用戶腳本可以顯示的系統信息。

#!/bin/bash

cat << EOF
disk) Show disk infomation.
mem) Show memory infomation.
cpu) Show cpu infomation.
*) QUIT!
EOF

read -p "Your option is: " option
if [ -z $option ]; then
    echo "You input nothing,QUIT!"
    exit 1
elif [ $option == disk ]; then
    fdisk -l
elif [ $option == mem ]; then
    free -m
elif [ $option == cpu ]; then
    lscpu
else
    echo "You input a illegal string,QUIT now!"
fi

在後面學習了迴圈之後,可以加上迴圈,使得用戶在輸入錯誤的情況下,反覆讓用戶輸入直到輸入正確的選項。

#!/bin/bash

cat << EOF
disk) Show disk infomation.
mem) Show memory infomation.
cpu) Show cpu infomation.
*) Again!
EOF

read -p "Your option is: " option

while [ "$option" != disk -a "$option" != mem -a "$option" != cpu -o "$option" == "" ]; do
    echo "You input a illegal string. Usage {disk|mem|cpu}, case sensitive."
    read -p "Your option is: " option
done

if [ $option == disk ]; then
    fdisk -l
elif [ $option == mem ]; then
    free -m
elif [ $option == cpu ]; then
    lscpu
fi

這個腳本的難點我覺得在於while迴圈中的判斷應該怎麼寫,$option是否應該加引號、字元串匹配右邊的字元(如disk)是否需要加引號、使用單中括弧還是雙中括弧、使用單引號還是雙引號。我也是一遍遍試直到瞎貓碰到死耗子才寫出來符合自己需求的bash代碼。

具體涉及的難點包括但《Bash腳本編程學習筆記04:測試命令test、狀態返回值、位置參數和特殊變數》文章開頭說的那些,因此這裡無法為大家做到準確的分析。

 

case語句

像上述腳本中,我們反覆對一個變數做字元串等值比較並使用了多分支的if語句。此類情況我們完全可以使用case語句來代替,使其更容易看懂。

其官方語法如下:

case word in
    [ [(] pattern [| pattern]…) command-list ;;]…
esac

case會將word和pattern進行匹配,一旦匹配到就執行對應的command-list,並且退出。

pattern基於bash的模式匹配,即glob風格。

pattern至少一個,可以有多個使用“|”分隔。

pattern+command-list成為一個子句(clause),如下。

[(] pattern [| pattern]…) command-list ;;

每個子句,都會以“;;”或者“;&”或者“;;&”結束。基本上只會使用“;;”。

;;:決定了一旦word第一次匹配到了pattern,就執行對應的command-list,並且退出。
;&和;;&:而這兩個是不會在第一次匹配到就立刻退出的,還會有其他後續的動作,幾乎很少用到,有需要的可以去看手冊。

word在匹配前會經歷:波浪符展開、參數展開、命令替換、算術展開和引號去除。

pattern會經歷:波浪符展開、參數展開、命令替換和算術展開。

當word的值是一個通配符的時候,表示預設的case。類似多分支if語句最後的else。

來個官方示例,簡單易懂。

#!/bin/bash

echo -n "Enter the name of an animal: "
read ANIMAL
echo -n "The $ANIMAL has "
case $ANIMAL in
  horse | dog | cat) echo -n "four";;
  man | kangaroo ) echo -n "two";;
  *) echo -n "an unknown number of";;
esac
echo " legs."

學會了case語句後,我們就可以對上面的多分支if語句的最後一個示例(顯示系統信息的)進行改寫,改為case語句的。應該不難,這裡不演示了,我們嘗試新的腳本。

我們嘗試寫一個bash服務類腳本,常見於CentOS 6系列的系統中的/etc/rc.d/init.d/目錄下。

  • 腳本的名稱一般就是服務名稱,不會帶“.sh”。
  • 服務腳本一般會創建一個空文件作為鎖文件,若此文件存在則表示服務處於運行狀態;反之,則服務處於停止狀態。
  • 腳本只能接收四種參數:start, stop, restart, status。
  • 我們並不會真正啟動某進程,只要echo即可。啟動時需創建鎖文件,停止時需刪除鎖文件。
  • 適當加入條件判斷使得腳本更健壯。
#!/bin/bash
#
# chkconfig: - 50 50
# Description: test service script
#

prog=$(basename $0)
lockfile="/var/lock/subsys/$prog"

case $1 in
    start)
        if [ -e $lockfile ]; then
            echo "The service $prog has already started."
        else
            touch $lockfile
            echo "The service $prog starts finished."
        fi
    ;;
    stop)
        if [ ! -e $lockfile ]; then
            echo "The service $prog has already stopped."
        else
            rm -f $lockfile
            echo "The service $prog stops finished."
        fi
    ;;
    restart)
        if [ -e $lockfile ]; then
            rm -f $lockfile
            touch $lockfile
            echo "The service $prog restart finished."
        else
            touch $lockfile
            echo "The service $prog starts finished."
        fi
    ;;
    status)
        if [ -e $lockfile ]; then
            echo "The service $prog is running."
        else
            echo "The service $prog is not running."
        fi
    ;;
    *)
        echo "Usage: $prog {start|stop|restart|status}"
        exit 1
    ;;
esac

腳本編寫完成後,要放入服務腳本所在的目錄、給予許可權、加入服務管控(chkconfig),最後就可以使用service命令進行測試了。

~]# cp -av case_service.sh /etc/rc.d/init.d/case_service
‘case_service.sh’ -> ‘/etc/rc.d/init.d/case_service’
~]# chmod a+x /etc/rc.d/init.d/case_service
~]# chkconfig --add case_service
~]# chkconfig case_service on

像這個服務類的腳本,我們在重啟時,可能執行先停止後啟動,也可能執行啟動。這些在啟動和停止時都有已經寫好的代碼了。如果可以將代碼進行重用的話,就可以減少很多代碼勞動。這就是之後要介紹的函數。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 微信公眾號: "Dotnet9" ,網站: "Dotnet9" ,問題或建議: "請網站留言" , 如果對您有所幫助: "歡迎贊賞" 。 C WPF之Material Design自定義顏色 閱讀導航 1. 本文背景 2. 代碼實現 3. 本文參考 1. 本文背景 主要介紹使用Material De ...
  • 生活中,如果1+2+3+4.....+100,大家基本上都會用等差數列計算,如果有人從1開始加,不是傻就是白X,那麼程式中呢,是不是也是這樣。今天無意中看到了尾遞歸,以前也寫過,但是不知道這個專業名詞,今天寫一下對比下性能問題。 今天主要是看到了尾遞歸,所以聯想到了這些,寫下這篇文章,其中也把Ben ...
  • 背景 通常,.Net 應用程式中的配置存儲在配置文件中,例如 App.config、Web.config 或 appsettings.json。從 ASP.Net Core 開始,出現了一個新的可擴展配置框架,它允許將配置存儲在配置文件之外,並從命令行、環境變數等等中檢索它們。 在傳統項目中,修改配 ...
  • 前言 導出功能幾乎是所有應用系統必不可少功能,今天我們來談一談,如何使用記憶體映射文件MMF進行記憶體優化,本文重點介紹使用方法,相關原理可以參考文末的連接 實現 我們以單次導出一個excel舉例(csv同理),excel包含1~n個sheet,在每個sheet中存儲的按行和列的坐標在單元格存儲具體數據 ...
  • 最近在處理客戶端安裝程式過程,有一個需求:需要檢測Windows平臺下安裝office 版本信息以及獲取使用的office是32 位還是64 位; 當檢測出office 位數為64位時,提示當前office 不支持程式的使用。 找了很多資料,一般情況下,是不能直接獲取office 安裝位數信息的;加 ...
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/7596897.html,記錄一下學習過程以備後續查用。 一、引言 接上一篇C#設計模式學習筆記:簡單工廠模式(工廠方法模式前奏篇),通過簡單工廠模式的瞭解,它的缺點就是隨著需求的變化我們要不停地修改工廠里 上一 ...
  • 為什麼想到這個呢,演算法什麼的又不太懂,這是 因為搭建VPN + BBR 與之簡直絕配 有的人搭建SSR ,配一個什麼銳速,還需要降內核版本, 而且還容易出錯,降了之後更加容易出現相容性問題,所以偶爾看到了google的BBR 擁塞阻塞演算法 演算法原理不知道,也不想去深究 。 原理 這篇博客 講得還是很 ...
  • 本篇中涉及到算術運算,使用了$[]這種我未在官方手冊中見到的用法,但是確實可用的,在此前的博文《Bash腳本編程學習筆記03:算術運算》中我有說明不要使用,不過自己忘記了。大家還是儘量使用其他的方法進行算術運算。 簡介 Bash具有三種迴圈結構: for迴圈。 while迴圈。 untile迴圈。 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 插件化的需求主要源於對軟體架構靈活性的追求,特別是在開發大型、複雜或需要不斷更新的軟體系統時,插件化可以提高軟體系統的可擴展性、可定製性、隔離性、安全性、可維護性、模塊化、易於升級和更新以及支持第三方開發等方面的能力,從而滿足不斷變化的業務需求和技術挑戰。 一、插件化探索 在WPF中我們想要開 ...
  • 歡迎ReaLTaiizor是一個用戶友好的、以設計為中心的.NET WinForms項目控制項庫,包含廣泛的組件。您可以使用不同的主題選項對項目進行個性化設置,並自定義用戶控制項,以使您的應用程式更加專業。 項目地址:https://github.com/Taiizor/ReaLTaiizor 步驟1: ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • Channel 是乾什麼的 The System.Threading.Channels namespace provides a set of synchronization data structures for passing data between producers and consume ...
  • efcore如何優雅的實現按年分庫按月分表 介紹 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能、輕量級針對分表分庫讀寫分離的解決方案,具有零依賴、零學習成本、零業務代碼入侵適配 距離上次發文.net相關的已經有很久了,期間一直在從事java相關的 ...
  • 前言 Spacesniffer 是一個免費的文件掃描工具,通過使用樹狀圖可視化佈局,可以立即瞭解大文件夾的位置,幫助用戶處理找到這些文件夾 當前系統C盤空間 清理後系統C盤空間 下載 Spacesniffer 下載地址:https://spacesniffer.en.softonic.com/dow ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 一、ReZero簡介 ReZero是一款.NET中間件 : 全網唯一開源界面操作就能生成API , 可以集成到任何.NET6+ API項目,無破壞性,也可讓非.NET用戶使用exe文件 免費開源:MIT最寬鬆協議 , 一直從事開源事業十年,一直堅持開源 1.1 純ReZero開發 適合.Net Co ...
  • 一:背景 1. 講故事 停了一個月沒有更新文章了,主要是忙於寫 C#內功修煉系列的PPT,現在基本上接近尾聲,可以回頭繼續更新這段時間分析dump的一些事故報告,有朋友微信上找到我,說他們的系統出現了大量的http超時,程式不響應處理了,讓我幫忙看下怎麼回事,dump也抓到了。 二:WinDbg分析 ...
  • 開始做項目管理了(本人3年java,來到這邊之後真沒想到...),天天開會溝通整理需求,他們講話的時候忙裡偷閑整理一下常用的方法,其實語言還是有共通性的,基本上看到方法名就大概能猜出來用法。出去打水的時候看到外面太陽好好,真想在外面坐著曬太陽,回來的時候好兄弟三年前送給我的鍵盤D鍵不靈了,在打"等待 ...