最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Shell腳本中until循環(huán)語句的用法詳解

 更新時間:2026年03月19日 09:53:36   作者:Jinkxs  
在 Linux Shell 編程世界中,循環(huán)結(jié)構(gòu)是控制程序流程、實現(xiàn)重復(fù)任務(wù)的核心工具之一,我們常聽到 for 和 while 循環(huán),但有一個低調(diào)卻實用的反向選手:until 循環(huán),今天,我們將深入探索 Shell 腳本中的 until 循環(huán)語句,需要的朋友可以參考下

引言

在 Linux Shell 編程世界中,循環(huán)結(jié)構(gòu)是控制程序流程、實現(xiàn)重復(fù)任務(wù)的核心工具之一。我們常聽到 forwhile 循環(huán),但有一個低調(diào)卻實用的“反向選手”——until 循環(huán)。它不像 while 那樣“條件為真時執(zhí)行”,而是“條件為假時才執(zhí)行”,這種逆向思維往往能在特定場景下帶來意想不到的簡潔與高效。

今天,我們將深入探索 Shell 腳本中的 until 循環(huán)語句,從最基礎(chǔ)的語法結(jié)構(gòu)講起,逐步過渡到復(fù)雜嵌套、文件處理、錯誤重試機(jī)制等實戰(zhàn)應(yīng)用,并穿插 Java 代碼對比,幫助你建立跨語言的編程思維。無論你是剛?cè)腴T Shell 的新手,還是希望深化腳本能力的老手,這篇文章都將為你打開一扇新的大門。

什么是 until 循環(huán)?

until 是 Shell 腳本中的一種循環(huán)控制結(jié)構(gòu),其基本思想是:

只要條件不成立(返回非零退出狀態(tài)),就一直執(zhí)行循環(huán)體;一旦條件成立(返回零退出狀態(tài)),則退出循環(huán)。

這與 while 循環(huán)正好相反。while 是“條件為真時執(zhí)行”,而 until 是“條件為假時執(zhí)行”。

基本語法結(jié)構(gòu)

until [ 條件表達(dá)式 ]
do
    # 循環(huán)體:當(dāng)條件為假時執(zhí)行的命令
    command1
    command2
    ...
done

或者使用雙括號或 test 命令:

until (( 表達(dá)式 )); do
    # 執(zhí)行語句
done
until test 條件; do
    # 執(zhí)行語句
done

簡單示例:倒計時器

讓我們從一個簡單的例子開始 —— 實現(xiàn)一個倒計時器,從 5 數(shù)到 0:

#!/bin/bash

counter=5

until [ $counter -lt 0 ]
do
    echo "倒計時: $counter"
    sleep 1
    counter=$((counter - 1))
done

echo "?? 發(fā)射!"

運(yùn)行結(jié)果:

倒計時: 5
倒計時: 4
倒計時: 3
倒計時: 2
倒計時: 1
倒計時: 0
?? 發(fā)射!

在這個例子中,循環(huán)會持續(xù)執(zhí)行,直到 $counter 小于 0(即條件為真)才停止。每次循環(huán)減少 1,模擬倒計時效果。

與 while 循環(huán)的對比

為了更清楚地理解 until 的獨(dú)特之處,我們將其與 while 對比:

使用 while 實現(xiàn)相同邏輯:

counter=5

while [ $counter -ge 0 ]
do
    echo "倒計時: $counter"
    sleep 1
    counter=$((counter - 1))
done

echo "?? 發(fā)射!"

對比分析:

特性untilwhile
條件判斷條件為假 → 執(zhí)行條件為真 → 執(zhí)行
語義傾向“直到…為止”“當(dāng)…的時候”
適用場景等待某事發(fā)生滿足條件時持續(xù)操作

關(guān)鍵區(qū)別在于語義和心理模型 —— until 更適合描述“等待某個目標(biāo)達(dá)成”的場景。

實戰(zhàn)場景一:等待服務(wù)啟動

在自動化部署或系統(tǒng)初始化過程中,常常需要等待某個服務(wù)(如數(shù)據(jù)庫、Web 服務(wù)器)啟動完成后再繼續(xù)后續(xù)操作。這時 until 就派上用場了!

#!/bin/bash

echo "? 正在等待 MySQL 服務(wù)啟動..."

until mysqladmin ping --silent; do
    echo "??  MySQL 未就緒,3 秒后重試..."
    sleep 3
done

echo "? MySQL 已啟動,繼續(xù)執(zhí)行后續(xù)任務(wù)..."

這段腳本會不斷嘗試連接 MySQL,直到成功為止。mysqladmin ping 成功時返回 0,失敗時返回非 0 —— 這正是 until 所需的“終止條件”。

提示:你可以將 mysqladmin ping 替換為 curl -f http://localhost:8080/health 來檢測 Web 服務(wù)健康狀態(tài)。

實戰(zhàn)場景二:用戶輸入驗證

有時我們需要用戶輸入特定格式的數(shù)據(jù),比如郵箱、數(shù)字、Y/N 確認(rèn)等。使用 until 可以優(yōu)雅地實現(xiàn)“直到輸入合法才繼續(xù)”的邏輯:

#!/bin/bash

read -p "請輸入您的年齡: " age

until [[ "$age" =~ ^[0-9]+$ ]] && [ $age -ge 1 ] && [ $age -le 120 ]; do
    echo "? 輸入無效,請輸入 1 到 120 之間的整數(shù)。"
    read -p "請重新輸入年齡: " age
done

echo "? 年齡已確認(rèn): $age 歲"

這個例子中,循環(huán)會持續(xù)提示用戶輸入,直到滿足三個條件:

  • 輸入是純數(shù)字
  • 數(shù)字 ≥ 1
  • 數(shù)字 ≤ 120

流程圖展示 until 循環(huán)工作原理

下面是一個用 Mermaid 繪制的 until 循環(huán)執(zhí)行流程圖,幫助你直觀理解其控制流:

從圖中可以看出,until 循環(huán)在每次迭代前都會檢查條件。只有當(dāng)條件為真(TRUE)時才會跳出循環(huán),否則反復(fù)執(zhí)行循環(huán)體。

與 Java 的類比:do-while vs until

雖然 Java 中沒有直接對應(yīng)的 until 關(guān)鍵字,但我們可以通過 do-whilewhile 模擬類似行為。

Java 示例:模擬倒計時

public class Countdown {
    public static void main(String[] args) throws InterruptedException {
        int counter = 5;
        // 使用 while 模擬 until 邏輯
        while (!(counter < 0)) {
            System.out.println("倒計時: " + counter);
            Thread.sleep(1000);
            counter--;
        }
        System.out.println("?? 發(fā)射!");
    }
}

或者更貼近 until 語義的方式 —— 使用 do-while 加反轉(zhuǎn)條件:

public class ServiceWaiter {
    public static void main(String[] args) {
        boolean isServiceReady = false;
        // 模擬服務(wù)未準(zhǔn)備好
        int attempts = 0;
        do {
            attempts++;
            System.out.println("?? 第 " + attempts + " 次檢查服務(wù)狀態(tài)...");
            // 模擬服務(wù)在第 3 次嘗試時準(zhǔn)備就緒
            if (attempts >= 3) {
                isServiceReady = true;
                System.out.println("? 服務(wù)已就緒!");
            } else {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } while (!isServiceReady); // 直到服務(wù)準(zhǔn)備好為止
        System.out.println("?? 繼續(xù)執(zhí)行后續(xù)任務(wù)...");
    }
}

Java 與 Shell 的思維映射:

  • Shell until condition ≈ Java while (!condition)
  • Shell 更注重“命令執(zhí)行狀態(tài)”(退出碼)
  • Java 更注重“布爾表達(dá)式值”

嵌套 until 循環(huán):多層控制結(jié)構(gòu)

有時候單一循環(huán)無法滿足需求,我們需要嵌套循環(huán)來處理更復(fù)雜的邏輯。例如:逐行讀取文件,對每行內(nèi)容再進(jìn)行字符級處理。

#!/bin/bash

# 創(chuàng)建測試數(shù)據(jù)
cat > test.txt <<EOF
apple
banana
cherry
EOF

line_num=1

while IFS= read -r line; do
    echo "第 $line_num 行: $line"

    char_index=0
    len=${#line}

    until [ $char_index -ge $len ]; do
        char="${line:$char_index:1}"
        echo "  字符 $((char_index + 1)): $char"
        char_index=$((char_index + 1))
    done

    line_num=$((line_num + 1))
    echo "---"

done < test.txt

輸出:

第 1 行: apple
  字符 1: a
  字符 2: p
  字符 3: p
  字符 4: l
  字符 5: e
---
第 2 行: banana
  字符 1: b
  字符 2: a
  字符 3: n
  字符 4: a
  字符 5: n
  字符 6: a
---
...

這個例子展示了如何在外層使用 while read 讀取文件,在內(nèi)層使用 until 遍歷字符串中的每個字符。

實戰(zhàn)場景三:文件鎖輪詢機(jī)制

在多進(jìn)程或多腳本協(xié)作環(huán)境中,經(jīng)常需要通過文件鎖機(jī)制避免資源沖突。我們可以用 until 實現(xiàn)“等待鎖文件消失后再繼續(xù)”的邏輯:

#!/bin/bash

LOCKFILE="/tmp/myapp.lock"

echo "?? 檢查鎖文件..."

until [ ! -f "$LOCKFILE" ]; do
    echo "? 鎖文件存在,等待 5 秒..."
    sleep 5
done

echo "?? 鎖已釋放,獲取資源中..."

# 創(chuàng)建自己的鎖
touch "$LOCKFILE"

# 執(zhí)行關(guān)鍵操作
echo "?? 正在處理數(shù)據(jù)..."
sleep 10

# 釋放鎖
rm -f "$LOCKFILE"
echo "? 任務(wù)完成,鎖已移除。"

這種模式非常適合批處理任務(wù)、定時任務(wù)或分布式腳本協(xié)調(diào)。

實戰(zhàn)場景四:網(wǎng)絡(luò)重連機(jī)制

在網(wǎng)絡(luò)不穩(wěn)定或遠(yuǎn)程服務(wù)偶發(fā)故障的環(huán)境中,自動重試是保障程序魯棒性的關(guān)鍵。until 循環(huán)非常適合實現(xiàn)帶最大重試次數(shù)的重連邏輯:

#!/bin/bash

MAX_RETRIES=5
retry_count=0

until curl -f https://httpbin.org/status/200 > /dev/null 2>&1; do
    retry_count=$((retry_count + 1))

    if [ $retry_count -gt $MAX_RETRIES ]; then
        echo "? 超過最大重試次數(shù) ($MAX_RETRIES),放棄連接。"
        exit 1
    fi

    echo "?? 第 $retry_count 次連接失敗,5 秒后重試..."
    sleep 5
done

echo "?? 連接成功!"

數(shù)學(xué)計算場景:求最小公倍數(shù)

until 不僅適用于系統(tǒng)管理,也能用于算法實現(xiàn)。比如,我們可以用它來找兩個數(shù)的最小公倍數(shù)(LCM):

#!/bin/bash

read -p "請輸入第一個正整數(shù): " num1
read -p "請輸入第二個正整數(shù): " num2

# 確保輸入合法
until [[ "$num1" =~ ^[0-9]+$ ]] && [ $num1 -gt 0 ]; do
    read -p "第一個數(shù)必須是正整數(shù),請重新輸入: " num1
done

until [[ "$num2" =~ ^[0-9]+$ ]] && [ $num2 -gt 0 ]; do
    read -p "第二個數(shù)必須是正整數(shù),請重新輸入: " num2
done

# 計算 LCM 的簡單方法:從較大數(shù)開始遞增,直到能被兩數(shù)整除
lcm=$num1
if [ $num2 -gt $lcm ]; then
    lcm=$num2
fi

until [ $((lcm % num1)) -eq 0 ] && [ $((lcm % num2)) -eq 0 ]; do
    lcm=$((lcm + 1))
done

echo "?? $num1 和 $num2 的最小公倍數(shù)是: $lcm"

雖然這不是最高效的算法(推薦用 GCD 方法),但它清晰展示了 until 在數(shù)值計算中的應(yīng)用。

單元測試風(fēng)格:驗證多個條件

在腳本開發(fā)中,有時需要確保多個前置條件都滿足后才執(zhí)行主邏輯。我們可以用 until + 邏輯組合實現(xiàn)“等待所有條件就緒”:

#!/bin/bash

check_condition_1() {
    # 模擬檢查磁盤空間
    df / | awk 'NR==2 {print $4}' | grep -qE '^[0-9]{5,}$'
}

check_condition_2() {
    # 模擬檢查網(wǎng)絡(luò)連通性
    ping -c 1 google.com > /dev/null 2>&1
}

check_condition_3() {
    # 模擬檢查配置文件存在
    [ -f "/etc/myapp/config.conf" ]
}

echo "?? 正在驗證系統(tǒng)環(huán)境..."

until check_condition_1 && check_condition_2 && check_condition_3; do
    echo "??  環(huán)境未準(zhǔn)備好,5 秒后重試..."
    sleep 5
done

echo "? 所有前置條件已滿足,啟動主程序..."

這種方式特別適合 CI/CD 環(huán)境、容器啟動腳本或云平臺初始化腳本。

高級技巧:結(jié)合函數(shù)與 until

until 與函數(shù)結(jié)合,可以寫出高度模塊化、可復(fù)用的腳本組件:

#!/bin/bash

# 定義重試函數(shù)
retry_until_success() {
    local max_attempts=$1
    shift
    local cmd=("$@")
    local attempt=0

    until "${cmd[@]}"; do
        attempt=$((attempt + 1))
        if [ $attempt -ge $max_attempts ]; then
            echo "? 命令執(zhí)行失敗,已達(dá)到最大重試次數(shù): $max_attempts"
            return 1
        fi
        echo "?? 第 $attempt 次重試: ${cmd[*]}"
        sleep 2
    done

    echo "? 命令執(zhí)行成功!"
}

# 使用示例
retry_until_success 3 curl -f http://example.com

retry_until_success 5 ls /nonexistent/path

retry_until_success 2 echo "Hello World"

這個 retry_until_success 函數(shù)接受最大重試次數(shù)和要執(zhí)行的命令,通用性極強(qiáng),可復(fù)用于各種場景。

性能考量:避免無限循環(huán)

雖然 until 很強(qiáng)大,但如果條件永遠(yuǎn)不成立,就會陷入無限循環(huán),導(dǎo)致腳本掛起、資源耗盡。因此,務(wù)必設(shè)置超時或最大重試次數(shù)。

危險示例(可能死循環(huán)):

# 如果 /tmp/flag 永遠(yuǎn)不會被創(chuàng)建,腳本將永遠(yuǎn)等待
until [ -f /tmp/flag ]; do
    sleep 1
done

安全改進(jìn)版:

timeout=60
start_time=$(date +%s)

until [ -f /tmp/flag ] || [ $(($(date +%s) - start_time)) -gt $timeout ]; do
    echo "? 等待標(biāo)志文件,已等待 $(( $(date +%s) - start_time )) 秒..."
    sleep 5
done

if [ ! -f /tmp/flag ]; then
    echo "? 超時!標(biāo)志文件未在 $timeout 秒內(nèi)出現(xiàn)。"
    exit 1
fi

echo "? 標(biāo)志文件已找到,繼續(xù)執(zhí)行..."

與其他 Shell 結(jié)構(gòu)的配合

until 可以和 ifcase、breakcontinue 等結(jié)構(gòu)靈活組合,構(gòu)建復(fù)雜邏輯。

示例:帶中斷機(jī)制的交互式菜單

#!/bin/bash

selected=false

until $selected; do
    echo "=== 主菜單 ==="
    echo "1) 查看系統(tǒng)信息"
    echo "2) 清理臨時文件"
    echo "3) 退出"
    read -p "請選擇操作 (1-3): " choice

    case $choice in
        1)
            echo "???  系統(tǒng)信息:"
            uname -a
            echo "---"
            ;;
        2)
            echo "?? 正在清理 /tmp 下的臨時文件..."
            rm -rf /tmp/*
            echo "? 清理完成。"
            ;;
        3)
            echo "?? 再見!"
            selected=true
            ;;
        *)
            echo "? 無效選擇,請輸入 1、2 或 3。"
            ;;
    esac

    if ! $selected; then
        read -p "按回車鍵返回菜單..." _
        clear
    fi
done

這個例子中,until 控制整個菜單循環(huán),case 處理具體選項,selected 變量作為退出條件。

網(wǎng)絡(luò)請求狀態(tài)監(jiān)控(結(jié)合 API)

現(xiàn)代運(yùn)維腳本常需與 REST API 交互。我們可以用 until 監(jiān)控異步任務(wù)的狀態(tài),直到完成:

#!/bin/bash

TASK_ID="task_12345"
API_URL="https://api.example.com/tasks/$TASK_ID/status"

echo "?? 查詢?nèi)蝿?wù) $TASK_ID 狀態(tài)..."

until status=$(curl -s "$API_URL" | jq -r '.status') && [ "$status" = "completed" ]; do
    case "$status" in
        "pending"|"running")
            echo "?? 任務(wù)狀態(tài): $status,10 秒后重查..."
            ;;
        "failed")
            echo "? 任務(wù)失敗!"
            exit 1
            ;;
        *)
            echo "??  未知狀態(tài): $status"
            ;;
    esac

    sleep 10
done

echo "?? 任務(wù) $TASK_ID 已完成!"

Java 對比:模擬 API 輪詢

下面是上述 Shell 腳本的 Java 版本,使用 HttpClientObjectMapper

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TaskPoller {
    private static final String TASK_ID = "task_12345";
    private static final String API_URL = "https://api.example.com/tasks/" + TASK_ID + "/status";
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        ObjectMapper mapper = new ObjectMapper();
        System.out.println("?? 查詢?nèi)蝿?wù) " + TASK_ID + " 狀態(tài)...");
        String status;
        do {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(API_URL))
                    .GET()
                    .build();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            JsonNode json = mapper.readTree(response.body());
            status = json.get("status").asText();
            switch (status) {
                case "pending", "running" -> {
                    System.out.println("?? 任務(wù)狀態(tài): " + status + ",10 秒后重查...");
                    Thread.sleep(10000);
                }
                case "failed" -> {
                    System.out.println("? 任務(wù)失?。?);
                    System.exit(1);
                }
                default -> System.out.println("??  未知狀態(tài): " + status);
            }
        } while (!"completed".equals(status));
        System.out.println("?? 任務(wù) " + TASK_ID + " 已完成!");
    }
}

注意:Java 版本需要引入 Jackson 依賴(如 com.fasterxml.jackson.core:jackson-databind)來解析 JSON。

實用工具函數(shù)庫:封裝 until 邏輯

為了提高腳本復(fù)用性,我們可以創(chuàng)建一個工具函數(shù)庫,集中管理常見的 until 模式:

#!/bin/bash

# utils.sh - until 循環(huán)工具庫

wait_for_file() {
    local file_path="$1"
    local timeout="${2:-60}"
    local interval="${3:-5}"

    local start_time=$(date +%s)

    echo "? 等待文件: $file_path"

    until [ -f "$file_path" ]; do
        local elapsed=$(( $(date +%s) - start_time ))
        if [ $elapsed -gt $timeout ]; then
            echo "? 超時!文件 $file_path 未在 $timeout 秒內(nèi)出現(xiàn)。"
            return 1
        fi

        echo "??  已等待 $elapsed 秒,$interval 秒后重試..."
        sleep $interval
    done

    echo "? 文件 $file_path 已就緒。"
}

wait_for_port() {
    local host="$1"
    local port="$2"
    local timeout="${3:-30}"
    local interval="${4:-3}"

    local start_time=$(date +%s)

    echo "?? 等待端口 $host:$port 開放..."

    until nc -z "$host" "$port" 2>/dev/null; do
        local elapsed=$(( $(date +%s) - start_time ))
        if [ $elapsed -gt $timeout ]; then
            echo "? 超時!端口 $host:$port 未在 $timeout 秒內(nèi)開放。"
            return 1
        fi

        echo "??  已等待 $elapsed 秒,$interval 秒后重試..."
        sleep $interval
    done

    echo "? 端口 $host:$port 已開放。"
}

wait_for_command() {
    local cmd="$1"
    local timeout="${2:-60}"
    local interval="${3:-5}"

    local start_time=$(date +%s)

    echo "??  等待命令成功執(zhí)行: $cmd"

    until eval "$cmd" >/dev/null 2>&1; do
        local elapsed=$(( $(date +%s) - start_time ))
        if [ $elapsed -gt $timeout ]; then
            echo "? 超時!命令未在 $timeout 秒內(nèi)成功。"
            return 1
        fi

        echo "??  已等待 $elapsed 秒,$interval 秒后重試..."
        sleep $interval
    done

    echo "? 命令執(zhí)行成功: $cmd"
}

然后在主腳本中引用:

#!/bin/bash

source ./utils.sh

wait_for_file "/var/log/app.log" 120 10
wait_for_port "localhost" 8080 45 5
wait_for_command "systemctl is-active myservice" 60 3

這種模塊化設(shè)計極大提升了腳本的可維護(hù)性和可測試性。

測試驅(qū)動開發(fā)(TDD)風(fēng)格腳本

雖然 Shell 腳本通常不強(qiáng)調(diào) TDD,但我們可以借鑒其思想 —— 先寫“期望條件”,再寫實現(xiàn)。

#!/bin/bash

# test_database_ready.sh

expect_database_ready() {
    # 期望:數(shù)據(jù)庫應(yīng)能響應(yīng)查詢
    mysql -e "SELECT 1;" > /dev/null 2>&1
}

echo "?? 運(yùn)行測試:數(shù)據(jù)庫是否就緒?"

until expect_database_ready; do
    echo "?? 數(shù)據(jù)庫未就緒,重試中..."
    sleep 5
done

echo "? 測試通過:數(shù)據(jù)庫已就緒!"

這種方式讓腳本邏輯更清晰,也便于后期擴(kuò)展測試用例。

最佳實踐總結(jié)

在使用 until 循環(huán)時,請牢記以下最佳實踐:

  1. ? 始終設(shè)置超時或最大重試次數(shù) —— 避免死循環(huán)。
  2. ? 提供清晰的日志輸出 —— 方便調(diào)試和監(jiān)控。
  3. ? 將復(fù)雜條件封裝成函數(shù) —— 提高可讀性和復(fù)用性。
  4. ? 優(yōu)先使用內(nèi)置命令或輕量工具 —— 如 test、[[ ]]nc、curl -f。
  5. ? 考慮并發(fā)安全 —— 在多實例環(huán)境下使用文件鎖或信號量。
  6. ? 記錄執(zhí)行時間 —— 用于性能分析和告警。
  7. ? 提供退出碼 —— 便于父腳本或調(diào)度系統(tǒng)判斷執(zhí)行結(jié)果。

高級應(yīng)用:動態(tài)條件生成

有時條件不是靜態(tài)的,而是根據(jù)上下文動態(tài)變化。我們可以結(jié)合數(shù)組、配置文件等實現(xiàn)靈活控制:

#!/bin/bash

# 從配置文件讀取需檢查的服務(wù)列表
mapfile -t services < services.conf

echo "?? 檢查以下服務(wù)狀態(tài): ${services[*]}"

all_ready=false

until $all_ready; do
    all_ready=true

    for service in "${services[@]}"; do
        if ! systemctl is-active --quiet "$service"; then
            echo "??  服務(wù) $service 未運(yùn)行"
            all_ready=false
        fi
    done

    if ! $all_ready; then
        echo "? 仍有服務(wù)未就緒,10 秒后重試..."
        sleep 10
    fi
done

echo "? 所有服務(wù)均已啟動!"

配置文件 services.conf

nginx
postgresql
redis-server
myapp-backend

監(jiān)控腳本:資源使用率閾值控制

企業(yè)級腳本常需監(jiān)控 CPU、內(nèi)存、磁盤等資源。我們可以用 until 實現(xiàn)“資源低于閾值才繼續(xù)”:

#!/bin/bash

CPU_THRESHOLD=80
MEM_THRESHOLD=90
DISK_THRESHOLD=85

echo "?? 監(jiān)控系統(tǒng)資源使用率..."

until \
    cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}') && \
    mem_usage=$(free | grep Mem | awk '{print $3/$2 * 100.0}') && \
    disk_usage=$(df / | tail -1 | awk '{print $5}' | sed 's/%//') && \
    (( $(echo "$cpu_usage < $CPU_THRESHOLD" | bc -l) )) && \
    (( $(echo "$mem_usage < $MEM_THRESHOLD" | bc -l) )) && \
    [ $disk_usage -lt $DISK_THRESHOLD ]; do

    echo "?? 當(dāng)前資源使用率 — CPU: ${cpu_usage%.*}%, 內(nèi)存: ${mem_usage%.*}%, 磁盤: ${disk_usage}%"
    echo "? 資源使用過高,等待 30 秒..."
    sleep 30
done

echo "? 資源使用率已降至安全范圍,繼續(xù)執(zhí)行任務(wù)..."

自動化部署流水線中的 until

在 CI/CD 流水線中,until 常用于等待構(gòu)建產(chǎn)物、鏡像推送完成、服務(wù)健康檢查通過等環(huán)節(jié):

#!/bin/bash

IMAGE_NAME="myapp:latest"
DEPLOYMENT_NAME="myapp-prod"

echo "?? 開始部署 $IMAGE_NAME 到 $DEPLOYMENT_NAME"

# 1. 構(gòu)建并推送鏡像
docker build -t $IMAGE_NAME .
docker push $IMAGE_NAME

# 2. 更新 Kubernetes Deployment
kubectl set image deployment/$DEPLOYMENT_NAME myapp-container=$IMAGE_NAME

# 3. 等待 Pod 就緒
echo "? 等待新 Pod 就緒..."

until kubectl rollout status deployment/$DEPLOYMENT_NAME --timeout=5s 2>/dev/null; do
    echo "?? 檢查部署狀態(tài)..."
    sleep 5
done

# 4. 驗證服務(wù)端點
echo "?? 驗證服務(wù)端點可達(dá)..."

until curl -f http://myapp.prod.svc.cluster.local:8080/health; do
    echo "?? 服務(wù)未響應(yīng),5 秒后重試..."
    sleep 5
done

echo "? 部署成功!??"

這種模式確保了部署過程的原子性和可靠性。

總結(jié):為什么你應(yīng)該掌握 until 循環(huán)

until 循環(huán)雖然不如 forwhile 那么常用,但在特定場景下具有不可替代的優(yōu)勢:

  • ? 語義清晰:表達(dá)“直到…為止”的意圖非常自然。
  • ? 邏輯簡潔:避免雙重否定或復(fù)雜條件反轉(zhuǎn)。
  • ? 健壯性強(qiáng):特別適合重試、輪詢、等待類任務(wù)。
  • ? 易于調(diào)試:條件判斷直觀,日志輸出明確。
  • ? 跨領(lǐng)域適用:從系統(tǒng)管理到 DevOps,從數(shù)據(jù)處理到網(wǎng)絡(luò)監(jiān)控。

掌握 until,不僅是學(xué)會一種語法結(jié)構(gòu),更是掌握了一種“逆向控制流”的思維方式 —— 有時候,從“失敗”出發(fā),反而更容易抵達(dá)“成功”。

最后的小貼士

  • 在腳本開頭加上 set -euo pipefail,提升健壯性。
  • 使用 shellcheck 工具檢查腳本語法和潛在問題。
  • 為長時間運(yùn)行的 until 循環(huán)添加進(jìn)度指示或日志輪轉(zhuǎn)。
  • 考慮使用 timeout 命令包裹整個 until 塊作為兜底保護(hù):
timeout 300 bash -c '
    until condition; do
        sleep 5
    done
' || echo "? 整體超時!"

無論你是系統(tǒng)管理員、DevOps 工程師、數(shù)據(jù)分析師,還是單純熱愛自動化腳本的開發(fā)者,until 循環(huán)都值得你收入工具箱。它或許低調(diào),但從不缺席關(guān)鍵時刻。

現(xiàn)在,打開你的終端,寫一個 until 循環(huán),讓機(jī)器為你“等到天荒地老”吧!

以上就是Shell腳本中until循環(huán)語句的用法詳解的詳細(xì)內(nèi)容,更多關(guān)于Shell腳本until循環(huán)語句的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Shell腳本注釋寫法

    Shell腳本注釋寫法

    這篇文章主要介紹了Shell腳本注釋的3種寫法,包含單行注釋的方法和多行注釋的多種方法,需要的朋友可以參考下
    2014-07-07
  • linux 中open()函數(shù)詳解及簡單實例

    linux 中open()函數(shù)詳解及簡單實例

    這篇文章主要介紹了linux 中open()函數(shù)詳解及簡單實例的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Shell日志分析常用命令和例子

    Shell日志分析常用命令和例子

    這篇文章主要介紹了Shell日志分析常用命令和例子,本文重點在一樣實現(xiàn)日志分析命令語句例子上,本文給出了10條常用的分析實例,需要的朋友可以參考下
    2014-12-12
  • 判斷文件是否存在的shell腳本代碼

    判斷文件是否存在的shell腳本代碼

    判斷文件是否存在的shell腳本,有詳細(xì)的注釋,很不錯,有需要的朋友不妨參考下
    2013-02-02
  • 普通用戶啟動supervisor報HTTP錯誤(strace)解決分析

    普通用戶啟動supervisor報HTTP錯誤(strace)解決分析

    這篇文章主要為大家介紹了普通用戶啟動supervisor報HTTP錯誤strace的問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Linux實現(xiàn)定時備份MySQL數(shù)據(jù)庫并刪除30天前的備份文件

    Linux實現(xiàn)定時備份MySQL數(shù)據(jù)庫并刪除30天前的備份文件

    這篇文章主要介紹了Linux實現(xiàn)定時備份MySQL數(shù)據(jù)庫并刪除30天前的備份文件,本文通過實例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-01-01
  • Shell腳本之文件批量創(chuàng)建與修改的簡單方法

    Shell腳本之文件批量創(chuàng)建與修改的簡單方法

    有時需要將文件內(nèi)容進(jìn)行修改,如果文件數(shù)量不多可以一個一個修改,那么如果文件數(shù)量很多一個一個修改很麻煩,這篇文章主要給大家介紹了關(guān)于Shell腳本之文件批量創(chuàng)建與修改的相關(guān)資料,需要的朋友可以參考下
    2021-06-06
  • linux shell字符串內(nèi)置的常用操作(獲取長度、查找、替換)

    linux shell字符串內(nèi)置的常用操作(獲取長度、查找、替換)

    在編寫shell程序時,經(jīng)常會涉及到字符串相關(guān)操作。有許多命令語句,如awk,sed都能夠做字符串各種操作。 事實上shell內(nèi)置一系列操作符號,能夠達(dá)到相似效果,使用內(nèi)部操作符會省略啟動外部程序等時間,因此速度會很的快。如果內(nèi)置的操作符能夠做到的,優(yōu)先使用內(nèi)置的
    2015-12-12
  • 基礎(chǔ)的Linux Shell技巧小結(jié)

    基礎(chǔ)的Linux Shell技巧小結(jié)

    這篇文章主要介紹了基礎(chǔ)的Linux Shell技巧小結(jié),是Linux入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下
    2015-07-07
  • 詳解Linux查找目錄下的按時間過濾的文件

    詳解Linux查找目錄下的按時間過濾的文件

    這篇文章主要介紹了Linux查找目錄下的按時間過濾的文件 ,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-05-05

最新評論

寿宁县| 兴山县| 涿鹿县| 昔阳县| 苏尼特右旗| 盈江县| 德保县| 莎车县| 乳山市| 磴口县| 莱州市| 菏泽市| 且末县| 富宁县| 平泉县| 奇台县| 新源县| 册亨县| 贵港市| 吉水县| 祁阳县| 恩平市| 津市市| 昌图县| 香港 | 海安县| 青浦区| 龙门县| 平潭县| 广饶县| 城固县| 林西县| 福州市| 高清| 涡阳县| 阜康市| 和平县| 隆林| 福鼎市| 云龙县| 南安市|