shell腳本之條件判斷,循環控制,exit詳解

if條件語句的語法及案例

一、基本語法結構

1. 單條件判斷
if [ 條件 ]; then命令1命令2...
fi
2. 雙分支(if-else)
if [ 條件 ]; then條件為真時執行的命令
else條件為假時執行的命令
fi
3. 多分支(if-elif-else)
if [ 條件1 ]; then命令1
elif [ 條件2 ]; then命令2
else命令3
fi
4. 嵌套結構
if [ 條件1 ]; thenif [ 條件2 ]; then命令1fi
else命令2
fi
5.多條件判斷語句case
case 變量名 in
值1)
指令1
;;
值2)
指令2
;;
值3)
指令3
;;
*)
默認
esac

二、條件測試語法

1. 數值比較
if [ $a -eq 10 ]; then ...    # 等于
if [ $a -ne 10 ]; then ...    # 不等于
if [ $a -gt 10 ]; then ...    # 大于
if [ $a -lt 10 ]; then ...    # 小于
if [ $a -ge 10 ]; then ...    # 大于等于
if [ $a -le 10 ]; then ...    # 小于等于
2. 字符串比較
if [ "$str" = "hello" ]; then ...    # 等于(注意用雙引號)
if [ "$str" != "hello" ]; then ...   # 不等于
if [ -z "$str" ]; then ...           # 字符串為空
if [ -n "$str" ]; then ...           # 字符串非空
3. 文件測試
if [ -e "file.txt" ]; then ...      # 文件或目錄存在
if [ -f "file.txt" ]; then ...      # 文件存在且為普通文件
if [ -d "dir" ]; then ...           # 目錄存在
if [ -r "file.txt" ]; then ...      # 文件可讀
if [ -w "file.txt" ]; then ...      # 文件可寫
if [ -x "script.sh" ]; then ...     # 文件可執行
4. 邏輯組合
# 使用 &&(邏輯與)
if [ -f "file.txt" ] && [ -r "file.txt" ]; then ...# 使用 ||(邏輯或)
if [ $a -eq 1 ] || [ $a -eq 2 ]; then ...# 使用 !(邏輯非)
if [ ! -d "dir" ]; then ...

三、案例示例

1. 判斷文件是否存在
#!/bin/bashif [ -e "data.txt" ]; thenecho "文件存在"cat data.txt
elseecho "文件不存在,創建中..."touch data.txt
fi
2. 檢查參數數量
#!/bin/bashif [ $# -ne 2 ]; thenecho "錯誤:需要兩個參數" >&2echo "用法:$0 參數1 參數2" >&2exit 1
elseecho "參數1: $1"echo "參數2: $2"
fi
3. 數值比較
#!/bin/bashread -p "請輸入一個數字: " numif [ "$num" -lt 0 ]; thenecho "負數"
elif [ "$num" -eq 0 ]; thenecho "零"
elseecho "正數"
fi
4. 字符串匹配
#!/bin/bashread -p "請輸入yes或no: " answerif [ "$answer" = "yes" ]; thenecho "你選擇了yes"
elif [ "$answer" = "no" ]; thenecho "你選擇了no"
elseecho "無效輸入"
fi
5. 檢查命令執行結果
#!/bin/bashif grep -q "error" log.txt; thenecho "日志中發現錯誤"mail -s "系統異常" admin@example.com < log.txt
elseecho "系統正常"
fi
6. 嵌套條件
#!/bin/bashread -p "請輸入年齡: " ageif [ "$age" -ge 18 ]; thenif [ "$age" -lt 60 ]; thenecho "成年人"elseecho "老年人"fi
elseecho "未成年人"
fi
7.case語句使用?
由用戶從鍵盤輸入一個字符,并判斷該字符是否為字母、數字或者其他字符, 并輸出
相應的提示信息。[root@kittod ~]# cat in.sh
#!/bin/bash
read -p "Please enter a character, press enter to continue: " KEY
case "$KEY" in
[a-z]|[A-Z])
echo "Input is letter"
;;
[0-9])
echo "Input is number"
;;
*)
echo "Input is other characters"
esac

四、高級語法

1. 使用?[[ ]]?替代?[ ]
# [[ ]] 支持更復雜的表達式
if [[ "$str" == hello* ]]; then ...    # 模式匹配
if [[ $a -gt 10 && $b -lt 20 ]]; then ...    # 邏輯組合
2. 使用?(( ))?進行數值比較
if (( a > 10 )); then ...    # 無需引號,支持算術表達式
3. 使用?test?命令
if test -f "file.txt"; then ...    # 等同于 [ -f "file.txt" ]

五、常見錯誤及注意事項

  1. 空格問題
    [?和?]?內部必須有空格,例如:

    # 正確
    if [ "$a" -eq 10 ]; then ...# 錯誤(缺少空格)
    if ["$a"-eq 10]; then ...
    
  2. 變量引用加引號
    防止變量為空時導致語法錯誤:

    # 正確
    if [ -z "$str" ]; then ...# 錯誤(當 $str 為空時會變成 [ -z ],語法錯誤)
    if [ -z $str ]; then ...
    
  3. 整數比較用?-eq,而非?=

    # 正確(數值比較)
    if [ "$a" -eq 10 ]; then ...# 錯誤(字符串比較)
    if [ "$a" = 10 ]; then ...
    

六、總結

語法結構適用場景示例
[ 條件 ]傳統條件測試[ -f "file.txt" ]
[[ 條件 ]]增強型條件測試(推薦)[[ $a -gt 10 && $b -lt 20 ]]
(( 條件 ))純數值比較(( a > 10 ))
test 條件等同于?[ ]test -d "dir"

合理使用?if?條件語句可以讓腳本根據不同情況執行不同邏輯,增強腳本的靈活性和健壯性。

exit詳細介紹

一、基本語法

exit [N]
  • N:可選參數,表示退出狀態碼(整數,范圍通常為?0~255)。
    • 若省略?Nexit?將返回最后一條命令的執行狀態碼
    • 狀態碼可通過?$??變量在腳本外獲取(例如在終端中執行?echo $?)。

二、退出狀態碼的含義

1. 標準狀態碼
  • 0:表示腳本正常執行完畢(無錯誤)。
  • 非?0:表示腳本異常終止或執行過程中出現錯誤(常見值:1~255)。
2. 常用非零狀態碼(約定俗成)
狀態碼含義說明
1通用錯誤(例如參數錯誤、文件不存在)。
2Shell 內置命令錯誤(如?cd?命令失敗)。
126命令存在但不可執行(如腳本無執行權限)。
127命令不存在(如拼寫錯誤的命令)。
130腳本被中斷信號(如?Ctrl+C)終止。
255非法退出狀態碼(超出范圍的數值會被取模為?255,例如?exit 300?等價于?exit 44)。

三、exit?的典型用法場景

1. 正常退出腳本(返回?0
#!/bin/bash
echo "腳本執行完成"
exit  # 等價于 exit 0
?
  • 執行后,通過?echo $??可獲取狀態碼?0
2. 異常退出并返回錯誤碼
#!/bin/bash
# 檢查文件是否存在
if [ ! -f "data.txt" ]; thenecho "錯誤:文件 data.txt 不存在!"exit 1  # 退出并返回錯誤碼 1
fiecho "文件存在,繼續執行..."
exit 0  # 正常退出
?
  • 若文件不存在,腳本輸出錯誤信息后終止,返回?1;否則返回?0
3. 根據命令執行結果決定是否退出
#!/bin/bash
# 嘗試創建目錄
mkdir -p "/data/app"
if [ $? -ne 0 ]; then  # $? 存儲上一條命令的狀態碼echo "創建目錄失敗!"exit 2  # 返回錯誤碼 2
fiecho "目錄創建成功"
exit 0
?
  • 通過?$??判斷前一條命令(mkdir)是否執行成功,失敗則退出并返回?2
4. 在函數中退出腳本
#!/bin/bash
check_disk_space() {free_space=$(df -h / | awk 'NR==2 {print $4}')if [ "$free_space" -lt "10G" ]; thenecho "磁盤空間不足!"exit 100  # 在函數中直接退出腳本,返回 100fi
}check_disk_space
echo "磁盤空間充足"  # 若空間不足,此行不會執行
exit 0
?
  • 函數中調用?exit?會直接終止腳本,無需返回值傳遞。

四、注意事項

1. 狀態碼的范圍限制
  • 狀態碼必須是?0~255 之間的整數,超出范圍會被自動取模(例如?exit 300?等價于?exit 44,因為?300 mod 256 = 44)。
2. 子進程中的?exit
  • 在子 Shell(如?(...)?或管道)中執行?exit僅會終止子 Shell,不影響父腳本。例如:
    (echo "子 Shell 開始"exit 1  # 子 Shell 退出,返回碼 1
    )
    echo "父腳本繼續執行"  # 此行會執行
    echo $?  # 輸出 1(子 Shell 的退出碼)
    
3. 與?return?的區別
  • exit:用于終止整個腳本,并返回狀態碼給系統(適用于腳本主流程)。
  • return:用于終止當前函數,并返回狀態碼給調用者(僅在函數內部使用)。
    func() {return 5  # 函數返回 5,不終止腳本
    }
    func
    echo $?  # 輸出 5(函數的返回值)
    

五、最佳實踐

  1. 明確返回狀態碼
    • 正常執行時返回?0,錯誤時返回有意義的非零碼(如?12?等),便于外部腳本或監控工具判斷執行結果。
  2. 提前退出
    • 在腳本開頭檢查必要條件(如權限、文件存在性),不滿足時盡早退出并提示錯誤。
  3. 避免濫用
    • 僅在需要終止腳本時使用?exit,避免在循環或分支中無意義地退出。

六、案例:帶狀態碼的腳本

#!/bin/bash
# 檢查當前用戶是否為 root
if [ "$USER" != "root" ]; thenecho "錯誤:必須以 root 身份運行!" >&2  # 錯誤信息輸出到 stderrexit 1  # 非 root 用戶,返回 1
fi# 檢查磁盤空間
free_space=$(df -BM / | awk 'NR==2 {print $4}' | tr -d 'M')
if [ "$free_space" -lt 100 ]; thenecho "警告:磁盤剩余空間不足 100MB!"exit 2  # 空間不足,返回 2
fiecho "腳本執行成功"
exit 0  # 正常退出,返回 0
?
  • 執行結果:
    $ ./script.sh          # 非 root 用戶執行
    錯誤:必須以 root 身份運行!
    $ echo $?              # 查看狀態碼
    1$ sudo ./script.sh     # root 用戶執行且空間充足
    腳本執行成功
    $ echo $?
    0
    
?

通過合理使用?exit,可以讓腳本更健壯、更易調試,尤其在自動化運維和腳本鏈調用中至關重要。

循環控制

一、for?循環

1. 基本語法(遍歷列表)
for 變量名 in 列表元素
do命令序列
done

  • 列表元素:可以是空格分隔的字符串、文件列表、命令輸出等。
  • 執行邏輯:變量依次取列表中的每個值,執行循環體。
2. 示例
示例 1:遍歷字符串列表
for fruit in apple banana cherry
doecho "當前水果:$fruit"
done
?

輸出

?
當前水果:apple
當前水果:banana
當前水果:cherry
示例 2:遍歷文件列表
for file in /etc/*.conf
doif [ -f "$file" ]; thenecho "文件:$file"fi
done
示例 3:遍歷命令輸出
for line in $(cat users.txt)
doecho "用戶:$line"
done
3. C 語言風格?for?循環(適用于數值迭代)
for ((初始值; 條件; 增量))
do命令序列
done
?
  • 初始值:變量初始化(如?i=1)。
  • 條件:循環繼續的條件(如?i<=10)。
  • 增量:變量更新(如?i++)。
?

示例

?
for ((i=1; i<=5; i++))
doecho "迭代次數:$i"
done
?

輸出

?
迭代次數:1
迭代次數:2
迭代次數:3
迭代次數:4
迭代次數:5

二、while?循環

1. 基本語法(條件為真時循環)
while [ 條件 ]
do命令序列
done
?
  • 執行邏輯:先判斷條件,若為真則執行循環體,重復直至條件為假。
2. 示例
示例 1:數值累加
sum=0
i=1
while [ $i -le 10 ]
dosum=$((sum + i))i=$((i + 1))
done
echo "1+2+...+10 = $sum"
?

輸出

?
1+2+...+10 = 55
示例 2:讀取文件逐行處理
while read -r line
doecho "行內容:$line"
done < file.txt
3. 無限循環
while true
doecho "無限循環中...(按 Ctrl+C 終止)"sleep 1
done

三、until?循環

1. 基本語法(條件為假時循環)
until [ 條件 ]
do命令序列
done
?
  • 執行邏輯:先判斷條件,若為假則執行循環體,重復直至條件為真(與?while?相反)。
2. 示例
n=10
until [ $n -le 0 ]
doecho "$n"n=$((n - 1))
done
?

輸出

?
10
9
8
7
6
5
4
3
2
1

四、循環控制關鍵字

1.?break:跳出當前循環
  • 用法
    for i in 1 2 3 4 5
    doif [ $i -eq 3 ]; thenbreak  # 當 i=3 時,跳出循環fiecho $i
    done
    
?

輸出

?
1
2
2.?continue:跳過當前迭代,繼續下一次循環
  • 用法
    for i in 1 2 3 4 5
    doif [ $i -eq 3 ]; thencontinue  # 當 i=3 時,跳過本次循環fiecho $i
    done
    
?

輸出

?
1
2
4
5
3.?break n?和?continue n:控制多層循環
  • n?表示跳出 / 跳過的循環層數(默認?n=1,即當前層)。
  • 示例(雙層循環)
    for i in a b c
    dofor j in 1 2 3doif [ $j -eq 2 ]; thenbreak 2  # 跳出兩層循環(即整個循環)fiecho "$i-$j"done
    done
    
?

輸出

?
a-1

五、循環常見應用場景

1. 批量文件操作
# 刪除所有 .bak 文件
for file in *.bak
dorm -f "$file"echo "已刪除:$file"
done
2. 進度條模擬
echo -n "進度:["
for ((i=0; i<=10; i++))
dosleep 0.5echo -n "#"
done
echo "] 完成"
?

輸出

?
進度:##########] 完成
3. 交互式循環(用戶輸入控制)
while true
doread -p "是否繼續?(y/n): " choicecase $choice in[Yy])echo "繼續執行...";;[Nn])echo "退出程序"break;;*)echo "無效輸入,請重新輸入";;esac
done

六、注意事項

  1. 變量引用加引號
    避免列表元素包含空格時被錯誤分割:

    # 錯誤(元素包含空格時分割錯誤)
    for str in "hello world" "hi bash"
    doecho $str  # 正確輸出每個元素
    done
    
  2. 避免無限循環
    在?while/until?循環中確保條件最終為真 / 假,否則需用?Ctrl+C?強制終止。

  3. 多層循環性能
    嵌套循環可能影響性能,盡量優化循環邏輯或使用更高效的工具(如?awksed)。

七、循環與數組結合

1. 遍歷數組元素
arr=("apple" "banana" "cherry")
for fruit in "${arr[@]}"
doecho "數組元素:$fruit"
done
2. 遍歷數組索引
arr=("a" "b" "c")
for i in "${!arr[@]}"  # ${!arr[@]} 獲取數組索引
doecho "索引 $i:${arr[$i]}"
done
?

輸出

?
索引 0:a
索引 1:b
索引 2:c

總結

循環類型特點適用場景
for?循環遍歷固定列表或數值范圍,簡潔直觀批量處理文件、已知次數的任務
while?循環條件為真時持續執行,適合未知次數的循環讀取文件、交互式操作
until?循環條件為假時持續執行,邏輯與?while?相反逆序計數、條件反轉場景
break/continue控制循環流程,跳出或跳過迭代復雜邏輯分支、提前終止循環

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83530.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83530.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83530.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

現代 Web 自動化測試框架對比:Playwright 與 Selenium 的深度剖析

現代 Web 自動化測試框架對比&#xff1a;Playwright 與 Selenium 的深度剖析 摘要&#xff1a;本文對 Playwright 與 Selenium 在開發適配性、使用難度、場景適用性及性能表現等方面進行了全面深入的對比分析。通過詳細的技術實現細節闡述與實測數據支撐&#xff0c;為開發者…

系統架構設計(十):結構化編程

定義 結構化編程是一種遵循清晰邏輯結構、避免使用 goto 的編程方法。它強調使用有限的三種基本控制結構來組織程序&#xff0c;提高程序的可讀性、可維護性和可測試性。 它是現代程序設計的基礎&#xff0c;被廣泛應用于命令式語言&#xff08;如 C、Pascal、Java&#xff0…

TC3xx學習筆記-UCB BMHD使用詳解(二)

文章目錄 前言Confirmation的定義Dual UCB: Confirmation StatesDual UCB: Errored State or ECC Error in the UCB Confirmation CodesECC Error in the UCB ContentDual Password UCB ORIG and COPY Re-programming UCB_BMHDx_ORIG and UCB_BMHDx_COPY (x 0-3)BMHD Protecti…

OTA與boot loader

OTA指的是無線升級&#xff0c;通常用于更新設備的固件或軟件&#xff0c;用戶不用手動操作&#xff0c;非常方便。而bootloader是啟動時加載操作系統的程序&#xff0c;負責硬件初始化和啟動流程。 首先&#xff0c;OTA是如何通過bootloader工作的。OTA下載更新包后&#xff0…

實驗六:FPGA序列檢測器實驗

FPGA序列檢測器實驗(遠程實驗系統) 文章目錄 FPGA序列檢測器實驗(遠程實驗系統)一、數字電路基礎知識1. 時鐘與同步2. 按鍵消抖原理代碼講解:分頻與消抖3. 有限狀態機(FSM)設計代碼講解:狀態機編碼與轉移4. 邊沿檢測與信號同步5. 模塊化設計二、實驗數字電路整體思想三…

jenkins部署

開發者將代碼push到git運維人員通過jenkins部署&#xff0c;自動到git上pull代碼通過maven構建成jar包&#xff0c;并結合dockerfile打包成鏡像&#xff0c;push docker鏡像到docker registry通過k8s發起 發布/更新 服務 操作 通過Jenkins部署&#xff0c;自動到Git上PULL代碼 …

BBR 的 buffer 動力學觀感

這周很忙&#xff0c;今天還加了一天班&#xff0c;但還是抽空實現了五一在安徽涇縣山區喝著一壺酒寫的 BBR ProbeRTT 的想法&#xff0c;沒多少行代碼&#xff0c;它真就消除了帶寬鋸齒&#xff0c;皮了個鞋&#x1f45e;&#xff0c;昨天我還在群里說了今天再說說 BBR 的&…

第9講、深入理解Scaled Dot-Product Attention

Scaled Dot-Product Attention是Transformer架構的核心組件&#xff0c;也是現代深度學習中最重要的注意力機制之一。本文將從原理、實現和應用三個方面深入剖析這一機制。 1. 基本原理 Scaled Dot-Product Attention的本質是一種加權求和機制&#xff0c;通過計算查詢(Query…

el-tree結合checkbox實現數據回顯

組件代碼 <el-tree:data"vertiList"show-checkboxnode-key"id":props"defaultProps"ref"treeRefx"class"custom-tree"check-change"handleCheckChange"> </el-tree>獲取選擇的節點 handleCheckChan…

OpenResty 深度解析:構建高性能 Web 服務的終極方案

引言 openresty是什么&#xff1f;在我個人對它的理解來看相當于嵌入了lua的nginx; 我們在nginx中嵌入lua是為了不需要再重新編譯,我們只需要重新修改lua腳本,隨后重啟即可; 一.lua指令序列 我們分別從初始化階段&#xff0c;重寫/訪問階段&#xff0c;內容階段&#xff0c;日志…

多商戶商城系統源碼解析:開發直播電商APP的技術底層實戰詳解

隨著直播電商的火爆&#xff0c;越來越多的創業者和企業都在尋求打造自己的多商戶商城系統&#xff0c;以實現“人、貨、場”三者的深度融合。然而&#xff0c;從一個簡單的電商平臺到一個功能完善的直播電商APP&#xff0c;其技術底層架構和實現過程并非一蹴而就。本文將從架構…

桌面端進程通信

以下是關于 Electron 桌面端進程通信的基本知識點總結: 一、Electron 進程模型基礎 1. 進程類型與職責 進程類型職責權限主進程(Main)創建窗口、系統級操作、IPC中樞完全Node.js訪問權限渲染進程(Renderer)展示Web內容、UI交互默認受限(可配置開啟Node.js)預加載腳本(Prelo…

openEuler24.03 LTS下安裝MySQL8.0.42

目錄 前提步驟 刪除原有mysql及maridb數據庫 安裝MySQL 啟動MySQL 啟動查看MySQL狀態 設置MySQL開機自啟動 查看登錄密碼 登錄MySQL 修改密碼及支持遠程連接 遠程連接MySQL 前提步驟 擁有openEuler24.03 LTS環境&#xff0c;可參考&#xff1a;Vmware下安裝openEule…

idea 保證舊版本配置的同時,如何從低版本升到高版本

文章目錄 前言idea 保證舊版本配置的同時,如何從低版本升到高版本1. 備份項目2. 下載最新的idea3. 安裝安裝包4. 導入idea2019舊配置5. 驗證前言 如果您覺得有用的話,記得給博主點個贊,評論,收藏一鍵三連啊,寫作不易啊^ _ ^。 ??而且聽說點贊的人每天的運氣都不會太差,…

填坑記: 古董項目Apache POI 依賴異常排除

當你看到NoSuchMethodError的時候&#xff0c;不要慌&#xff0c;深呼吸&#xff0c;這可能只是JAR包版本的問題… 引子&#xff1a;一個平靜的周二下午 那是一個看似平常的周二下午&#xff0c;系統運行良好&#xff0c;開發團隊在有條不紊地推進著新功能的開發。突然&#x…

CAPL Class: TcpSocket (此類用于實現 TCP 網絡通信 )

目錄 Class: TcpSocketacceptopenclosebindconnectgetLastSocketErrorgetLastSocketErrorAsStringlistenreceivesendsetSocketOptionshutdown函數調用的基本流程服務器端的基本流程客戶端的基本流程Class: TcpSocket學習筆記。來自CANoe幫助文檔。 Class: TcpSocket accept /…

微信小程序的開發及問題解決

HttpClient 測試例子 SpringBootTest public class HttpClientTest {/*** 測試通過httpclient發送get方式的請求*/Testpublic void testGET() throws IOException {//創建httpclient對象CloseableHttpClient httpClient HttpClients.createDefault();//創建請求對象HttpGet ht…

foreach中使用await的問題

目錄 1.說明 2.示例 3.解決方案 1.說明 在foreach中調用異步方法&#xff0c;即使使用了await&#xff0c;不會依次執行每個異步任務&#xff0c;也就是說Array.prototype.forEach不會等待 Promise 完成&#xff0c;即使你在回調函數中返回一個 Promise&#xff0c;forEach …

Linux調試生成核心存儲文件

1.核心存儲文件配置&#xff1a; 不知道理解對不對&#xff0c;Linux中的核心存儲文件的配置是在/proc/sys/kernel/core_pattern中的&#xff0c;使用 cat /proc/sys/kernel/core_pattern # 打印出 |/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E表示核…

Compose筆記(二十三)--多點觸控

這一節主要了解一下Compose中多點觸控&#xff0c;在Jetpack Compose 中&#xff0c;多點觸控處理需要結合Modifier和手勢API來實現&#xff0c;一般通過組合 pointerInput、TransformableState 和 TransformModifier 來創建支持縮放、旋轉和平移的組件。 一、 API 1. Pointer…