Overview of Content
在這篇文章中,我們將探討 Shell 腳本中的條件語句及其高級特性
從基本的 if-then
語句到複雜的條件測試和進階的 if-then 高級特性,我們將一一介紹各種條件語句的用法。你將了解如何使用 if-then 語句來執行不同的操作,以及如何使用 test
命令進行條件測試
此外,我們還將探討 if-then 高級特性和 case-in 命令的使用方法,幫助您更好地理解並運用 Shell 腳本中的條件語句。無論您是初學者還是有經驗的開發者,這篇文章都將為您提供全面且易於理解的概觀,幫助您提升 Shell 腳本編程的能力。
腳本結構化:可以 依照邏輯判斷去執行;這一類命令會根據條件去跳躍執行,這樣的命令通就稱為 結構化命令 (
structured command
)
寫文章分享不易,如有引用參考請詳註出處,如有指導、意見歡迎留言(如果覺得寫得好也請給我一些支持),感謝 😀
個人程式分享時比較注重「縮排」,所以可能不適合手機的排版閱讀,建議切換至「電腦版」、「平板版」視窗看
if-then 語句
如同在多個程式語言中使用的 if
判斷,其格式如下
if command
then
commands
fi
# 使用 `;` 符號的另一種寫法 -----------------
if command ; then
commands
fi
if-then 的判斷
● if-then
語句的是用來判斷 command 的執行結果,這個 執行結果就是退出碼 (exit status code),而退出碼成功的定義則是 0;所以 command 執行完返回 0 則這個 if-then
就會判斷成立
● 這與一般程式的 if 語句判斷稍有不同,如果使用一般程式語言來說那我們就可改寫成如下
// Kotlin, Java or C... if(command() == 0) { // do some commands }
對應 Shell 判斷(上下範例是相同的判斷)
# Shell if command ; then fi
● if-then
範例:
A. 判斷運行的指令成功、失敗
#!/bin/bash
# 成功,exit code 0
if ls -laF ; then
echo "command done."
fi
# 失敗,exit code 非 0
if ABC ; then
echo "command done2."
fi
運行結果
B. 使用多個指令 + 區域變數
#!/bin/bash
userName=alien
# 多個命令 (cat, grep
# 使用 `$` 引用區域變數
if cat /etc/passwd | grep -i $userName ; then
echo "command done."
fi
運行結果
C. 嵌套 if-then
判斷
#!/bin/bash
if ls -laF ; then
echo "command done."
if ABC ; then
echo "command done2."
fi
fi
運行結果
if-then-else 語句
● if-then-else
語句重點是多了 else 處理,當 if 命令執行後的退出碼不為 0 時,else 內容就會執行;格式如下
if command ; then
commands
else
commands
fi
● if-then-else
語句使用範例:
#!/bin/bash
if Yoyo ; then
echo "command done."
else
# 上面指令返回錯誤碼不為 0 時就執行
echo "command fail=($?)"
fi
if-then-elif-then 語句:多判斷
● if-then-elif-then
語句可以解決 if-then
多嵌套導致腳本程式看起來不優雅的問題(多嵌套會導致波動拳);格式如下
case
命令也可以解決 (下面小節會介紹)
if command1 ; then
commands1
elif command2 ; then
commands2
elif command3 ; then
command3
fi
● if-then-elif-then
使用範例:
以下還多了 else 處理所有情況都不符合的狀況
#!/bin/bash
if grep "ALIEN" /etc/passwd ; then
echo "ALIEN exists"
elif grep "Alien" /etc/passwd ; then
echo "Alien exists"
elif grep "alien" /etc/passwd ; then
echo "alien exists"
else
echo "No relate with alien"
fi
複合執行:&&
前方必須成立
● &&
執行:多個條件 都必須符合才算成立(退出碼為 0 代表成功),格式如下
<前方指令> && <後方指令>
也就是說前方指令成功,後方指令才會運行,範例如下:
#!/bin/bash
if ls -laF && pwd; then
echo "command done."
else
echo "command failure."
fi
複合執行:||
前方不能成立
● ||
執行:與 &&
執行相反,只有當前方指令執行失敗時(退出碼為非 0 代表失敗),後方指令才會執行,格式如下
<前方指令> || <後方指令>
範例如下:
cd e || echo "cd failed"
● 善用這個特性,甚至不需要使用
if
判斷句,也可以控制結構流程## --------------------------------------- # cd e || echo "cd failed" # 相當於如下程式 #!/bin/bash cd e 2> /dev/null if [ $? -ne 0 ]; then echo "cd failed" fi
test 命令:比較數值、字符串、文件
前面我們說到 if-then
語句都是判斷退出碼(exit status code
),如果 要判斷退出碼之外的條件就必須使用 test 命令;test 命令之後是 判斷,格式如下:
# 單獨使用 test 命令
test condition
if-then
語句使用 test 命令時,格式如下:
# 用法 1
if test condition ; then
commands
fi
# 用法 2
if [ condition ] ; then
commands
fi
● 如果 test 命令中的判斷成立,則 test 會退出並返回狀態碼 0
#!/bin/bash if test ; then echo "empty test done." else echo "empty test fail=($?)" fi
test 命令後面的 condition 不寫時,則退出碼為「非零」(代表失敗);
●
if-then
語句除了使用 test 命令之外,還可以使用中括號[ ]
替代 test 命令#!/bin/bash if [ "Hello" ] ; then echo "test done." else echo "test fail=($?)" fi
Condition:「數值」比較
● 如果需要對於數字作比較(比大小、是否等於... 等等);下表列出了列出 test 命令比較數值的 options
功能 | options | 使用 |
---|---|---|
相等 | -eq | n1 -eq n2 |
不等於 | -ne | n1 -ne n2 |
大於等於 | -ge | n1 -ge n2 |
大於 | -gt | n1 -gt n2 |
小於等於 | -le | n1 - n2 |
小於 | -lt | n1 - n2 |
● test condition 只能處理整數比較,不能比較浮點數否則會失敗
#!/bin/bash
varA=100
varB=1
if [ $varA -eq $varB ] ; then
echo "A == B"
elif [ $varA -lt $varB ] ; then
echo "A <= B"
elif [ $varA -le $varB ] ; then
echo "A < B"
elif [ $varA -gt $varB ] ; then
echo "A >= B"
elif [ $varA -ge $varB ] ; then
echo "A > B"
fi
Condition:「字符串」比較
● String 字串的比較是透過 ASCII Code 值比較;下表列出了列出 test 命令比較數值的 options
功能 | options | 使用 |
---|---|---|
相同 | = | n1 = n2 |
不相同 | != | n1 != n2 |
小於 | < | n1 < n2 |
大於 | \> | n1 > n2 |
字串長度非 0 | -n | -n n1 |
字串長度 0 | -z | -z n1 |
● 字串 大於 需要加跳脫字元
\
,避免腳本誤認為重新導向符號 (會變成判斷輸出一個文件是否成功)
A. 字串相等性比較:字串的比較有大小寫之分
#!/bin/bash
if [ $USER = "alien" ] ; then
echo "Account is alien."
fi
if [ $USER != "Alien" ] ; then
echo "Account is not Alien."
fi
B. 字串大小比較:其比較的其實也是 ASCII Code 的數值
#!/bin/bash
# 注意跳脫符號
if [ "Alien" /> "alien" ] ; then
echo "Alien > alien"
else
echo "Alien < alien"
fi
ASCII Code 值:
a
-> 96,A
-> 65
●
>
要使用跳過符號(\>
),否則會被認成重新導向 (你執行腳本後就產生一個 alien 檔案,並且比較還錯誤)如果認成重新導向,那 test 命令就會判斷重新導向的退出碼是否為 0,如果為 0 則 test 命令也會給外部退出碼 0
C. 字符串是否存在:判斷字串的操作符要放置在字串之前
#!/bin/bash
var1="Apple"
var2=""
if [ -n $var1 ] ; then
echo "var1 not empty."
fi
if [ -z $var2 ] ; then
echo "var2 is empty."
fi
# 未定義的變量也可以判斷
if [ -z $var3 ] ; then
echo "var3 is empty."
fi
未被定義的變量也可以判斷,不過會被判斷為空字串
Condition:「文件」比較
● test 命令的判斷,在腳本中最常用的就是 測試 Linux 文件系統上文件、目錄的狀態;下表為常用的文件判斷相關 test 命令
功能 | options | 使用 |
---|---|---|
是否是一個目錄 (directory) | -d | -d file |
是否是一個檔案 (file) | -f | -f file |
檔案是否存在 (exist) | -e | -e file |
檔案是否可讀(readable) | -r | -r file |
檔案是否可寫(writeable) | -r | -w file |
檔案是否可執行 (exec) | -x | -x file |
檔案是否非空 | -s | -s file |
檔案是否屬於當前用戶 | -O | -O file |
檔案是否與當前用戶相同群組 | -G | -G file |
檔案新舊比較(新為主) | -nt | file1 -nt file 2 (檢查 file1 是否比 file2 新) |
檔案新舊比較(舊為主) | -ot | file1 -ot file 2 (檢查 file1 是否比 file2 舊) |
這裡只寫幾個比較特別的檔案判斷
A. 文件所屬、群組判斷:
#!/bin/bash
if [ -O /etc/passwd ] ; then
echo "$USER is the onwer of /etc/passwd file."
else
echo "$USER is not the onwer of /etc/passwd file."
fi
if [ -G $HOME ] ; then
echo "$HOME group is same as $USER."
else
echo "$HOME group is not same as $USER."
fi
B. 文件新舊比較:直接寫文件名就可相互比較
選項
-nt
、-ot
不會判斷檔案是否存在,如果檔案不存在它 -可能會返回錯的結果!!
#!/bin/bash
if [ str_3.sh -nt str_4.sh ] ; then
echo "The file of 'str_3.sh' is new than 'str_4.sh'"
else
echo "The file of 'str_3.sh' is not new than 'str_4.sh'"
fi
if [ str_4.sh -ot str_3.sh ] ; then
echo "The file of 'str_4.sh' is old than 'str_3.sh'"
else
echo "The file of 'str_4.sh' is not old than 'str_3.sh'"
fi
非 Condition:「!」符號
● 非 Condition 判斷只需要 在 test 命令之前添加 !
即可進行非的判斷
#!/bin/bash
# 使用 `!` 進行非判斷
if [ ! -e $PWD/str_100.sh ] ; then
echo "The file of '$PWD/str_100.sh' is not exist."
fi
●
!
之間必須使用空格格開
複合 test 條件
● 使用 test 命令也可以允許多個邏輯條件判斷,其使用方式如下
A. OR 運算:其中一個成立,就算成立 [ condition1 ] || [ condition2 ]
||
可以對應 test 命令的 option-o
,也就是[ condition1 -o condition2 ]
B. AND 運算:全部成立,就算成立 [ condition1 ] && [ condition2 ]
&&
可以對應 test 命令的 option-a
,也就是[ condition1 -a condition2 ]
● 複合條件範例:
#!/bin/bash
if [ -G $HOME ] && [ -O $HOME ] ; then
echo "The $HOME is same group and owner of $USER."
fi
if [ -w /etc/group ] || [ -w /etc/passwd ] ; then
echo "The /etc/group or /etc/passwd is writeable."
fi
if-then 高級特性
bash shell 提供了幾個高級特性可以使用:1. 數學表達式的雙括號、2. 高級字串處理功能的雙方括號
雙括號:針對計算 (( ))
● 使用雙括號時的 if
判斷,就可以依照原先程式中的 if
判斷,也就是數值非 0 時才進入條件句(類似於開發用的程式的判斷),概念程式如下
if (( 1 )); then
echo "Hello 1." # 數值非 0, 所以會進入判斷
fi
● 雙括號可以提供更高級的數學運算式(很像高級編程中的運算),其格式為:(( experssion ))
;experssion 如下表
● 雙括號內不用使用
$
符號 !! 就可引用外部變數~
● 雙括號內部會假設變數內容皆為「數值」!可以用來判斷使用者輸入的數值,避免「字符的數字」與「數」搞混,可以用這個特性在比較判斷上
功能 | 符號 |
---|---|
後增 | val++ |
後減 | val-- |
先增 | ++val |
先減 | --val |
Not 邏輯 | ~val |
反位 | !val |
幂運算 | val ** |
左位移 | val >> |
右位移 | val << |
與運算 | val1 & val2 |
或運算 | val1 | val2 |
邏輯與 | val1 && val2 |
邏輯或 | val1 || val2 |
#!/bin/bash
var=10
if (( var ** 2 > 99 )) ; then
echo "var squre big then 99."
fi
(( --var ))
echo "var:$var"
echo "var: $(( var >> 1 ))"
雙方括號:針對字串 [[ ]]
● 雙方括號則是針對字符串的高級特性,它除了 test 命令字串比較,還 拓展了匹配模式,其格式:[[ expression ]]
● 並不是每個 Shell 都支持雙方括號(bash shell 支援)
#!/bin/bash
if [[ $USER == al* ]] ; then
echo "Hello, $USER"
else
echo "Who are you?"
fi
case-in 命令
如果有一組固定的答案,那使用 case 命令可以讓 Shell 看起來更整潔(大多是用在字符串配對時使用);其格式如下
使用 3 個符號
)
、;;
、case/esac
case variable in
pattern1) commands1;;
pattern2 | patter3) command2;;
patter*) command3;
*) default commands;;
esac
case-in 使用
● 使用 case-in 命令取代 if-then 命令!(注意結尾使用雙分號 ;;
)
#!/bin/bash
case $USER in
Apple)
echo "I got the Fruit";;
Testing)
echo "In Testing account";;
alien | Alien)
echo "Hello $USER";;
*)
echo "Other account...?";;
esac
● 其他非預設 case 可以使用
*)
來擷取
更多 Linux Shell 知識
Linux 環境、服務:用戶、權限管理
● Linux 環境、服務、管理:
在這個主題中,你可以探索各種 Linux 環境、服務和管理相關的重要概念…
● 了解 Linux 組成:內核責任、GNU 工具、桌面環境 | 基礎版到發行版
在這裡,你將了解 Linux 系統的基本組成部分,包括內核、GNU 工具和桌面環境,並了解不同 Linux 發行版之間的差異
● 探索 X Window 服務與桌面環境:Linux 視窗 XWindow 服務、D-Bus 機制
這裡探討了 Linux 系統中 X Window 服務和 D-Bus 機制的工作原理,讓你深入了解桌面環境的背後運作方式
● Linux 系統管理入門:安全性、用戶管理與權限設定指南
在這個指南中,你將學習如何管理 Linux 系統,包括安全性、用戶管理和權限設定,以確保系統的安全和有效運作
● 認識身份驗證與權限管理:UNIX UID、使用者驗證與 PAM | PAM 設定
這裡介紹了 UNIX 系統中的身份驗證機制和權限管理方式,包括 UNIX UID、使用者驗證和 PAM(
Pluggable Authentication Modules
)設定
Linux Shell 相關知識
● Linux Shell 相關知識:
這個主題涵蓋了各種與 Linux Shell 相關的知識,從基礎到進階都有…
● Shell 基礎知識:包括 Shell 的基礎使用以及差異,還有變數以及計算
● 認識命令行:Shell 類型、命令差異 | Sub Shell 關係 | Builtin 命令
這裡介紹了命令行中不同類型的 Shell,以及各種 Shell 命令之間的區別和內建命令的用法
● Shell 全局及區域變數、特殊變數及環境變數 | Shell 啟動順序 | Array 變數
學習如何在 Shell 中使用全局變數、特殊變數和環境變數,以及如何設置和管理這些變數
● 探索腳本與命令:Shell 腳本的必備相關知識 | 腳本的數學運算
這裡介紹了 Shell 腳本的基本知識和常用技巧,包括如何執行腳本和進行數學運算
● Shell 結構化
● Shell 腳本程式中的條件語句和高級特性 | Shell 結構化 & 判斷
該篇文章是介紹結構化腳本的基礎以及特殊的高級技巧,轉著於腳本中的邏輯判斷
● 掌握 Bash 腳本中的迴圈與循環控制技巧 | Shell 結構化 & 循環
接著是腳本中的循環與控制的技巧,它可以讓我們在 Shell 腳本中有更多的判斷與技巧
● 探索 Shell 函數與腳本庫 | Shell 結構化 & 函數
這裡你將會學在到結構化腳本的重要技巧「函數」,它可以讓你建立可重複利用的腳本,以節省我們之後開發的時間
● Shell 掌握參數處理與用戶輸入技巧 | Shell 結構化 &輸入互動
不可互動的腳本有時候相對無趣,這篇文章有分享如何讓腳本與使用者產生交互互動,並依照使用者輸入的參數做讀取
● Shell script 進階
● Shell 命令輸入與輸出指南:掌握標準文件描述符與重定向 | 臨時文件
掌控 Shell、指令的輸出輸入是成為進階使用 CLI 之人必經的一課,透過這篇文章可以了解到輸出輸入、臨時文件等等資訊
● 探索 Linux 訊號與後台進程管理:安排定期啟動腳本 | 運行時啟動腳本
信號可以算是 Shell 腳本與 Linux 系統之間的通訊方式,透過這個文章,我們可以了解到信號與 Shell 腳本的安排時間
Linux 硬體規劃:檔案系統、分區
● Linux 硬體規劃:檔案系統、分區:
最後,這個主題涵蓋了 Linux 系統中硬體結構相關的重要概念…
● Shell 文件和目錄操作的常用命令和技巧 | 尋找檔案
這裡介紹了 Shell 中常用的文件和目錄操作命令,包括如何尋找文件和管理文件系統
● 深入探索 Linux 文件系統與硬體管理 | 分區、檔案系統、邏輯卷 | inode
學習如何管理 Linux 文件系統,包括分區、文件系統和邏輯卷等相關概念,以及文件系統中的 inode 機制
● 理解 Unix/Linux 設備偵測、建立 | 認識與使用 udevd | SCSI 與 Linux 核心
這裡介紹了 Unix/Linux 系統中的設備偵測和管理,包括如何使用 udevd 和 SCSI 相關的 Linux 核心知識