HOWTO · Bash

如何讓 Bash Shell 指令碼暫停 X 秒

學會在 Bash 中使用 sleep 和 read,讓指令碼定時暫停或等待使用者輸入。

本頁內容

Bash 指令碼可以暫停,讓讀者有時間看完訊息、等待互動輸入,或在執行下一個命令前稍作停頓。若要等待一段時間,使用 sleep;若要等候輸入,使用 read。這兩種方式控制指令碼何時繼續執行,但單純延遲並不能協調多個程序對共用檔案的存取。

暫停 Bash 指令碼 X 秒

使用 sleep 搭配整數秒數,就能延遲執行下一個命令,而且必須提供等待時間。sleep 手冊 說明了這個命令;是否支援小數秒或時間單位後綴,則取決於系統安裝的 sleep 實作。

以下完整的 Bash 指令碼會先顯示訊息,提出等待一秒的要求,然後再顯示另一則訊息:

#!/usr/bin/env bash
printf '%s\n' 'The script is starting.'
sleep 1
printf '%s\n' 'One second wait requested.'

要求的延遲時間只是目標,不保證實際經過的時間恰好相同;系統排程可能讓等待時間更長。若要每隔一段整數秒數重複執行某項工作,可以把該工作和 sleep 放進迴圈。讓迴圈只處理明確的工作,確保每次重複都有清楚的效果。

暫停 Bash 指令碼一段時間

將整數秒數存入變數,並在傳給 sleep 時為變數展開加上引號。以下指令碼預設等待五秒;也可以透過環境變數 N 指定其他值:

#!/usr/bin/env bash
N=${N:-5}
sleep "$N"
printf 'Requested a %s-second wait.\n' "$N"

例如,執行 N=8 ./your-script.sh 會只在這次執行時使用該值。這個值必須是系統所安裝的 sleep 命令可接受的有效時間。加上引號可以避免字詞分割和路徑名稱展開,但無法讓任意輸入自動成為有效時間;若值來自使用者或其他不可信來源,請先驗證。

在 Bash 中,也可以使用 $RANDOM 將隨機數縮小到指定範圍,產生介於一至三秒的整數秒延遲:

#!/usr/bin/env bash
delay=$((1 + RANDOM % 3))
printf 'Requested a %s-second wait.\n' "$delay"
sleep "$delay"

隨機延遲可以讓不同次執行有不同的開始時間,但無法確保兩次執行不會同時寫入同一個檔案。若指令碼會共用資源,請使用適當的鎖定或協調機制。

暫停 Bash 指令碼,直到使用者輸入

Bash 的 read 命令會等待標準輸入的一整行。在互動式終端機中,使用者通常按下 Enter 後便會完成輸入。使用 -r 可讓輸入中的反斜線保持原樣,-p 則可顯示提示訊息:

#!/usr/bin/env bash
if read -r -p 'Press Enter to continue: ' reply; then
    printf '%s\n' 'Continuing.'
else
    printf '%s\n' 'No input line was available.'
fi

這種寫法預期會有互動式輸入,若一直沒有完整的一行,指令碼可能會無限期等待。如果標準輸入已到達檔案結尾或被重新導向,read 可能在未取得輸入行時返回;檢查它的狀態,就能處理這種情況。Bash read 參考手冊 說明了相關選項與行為。

將定時暫停與使用者輸入暫停相結合

若要讓輸入可以提早結束等待,而逾時也能讓指令碼繼續,請使用 Bash 的 read -t。逾時值以秒為單位,系統排程可能使實際等待更久。以下範例會指出是哪種情況讓指令碼繼續:

#!/usr/bin/env bash
if read -r -t 5 -p 'Continue now, or wait for the timeout: ' reply; then
    printf '%s\n' 'Input received; continuing.'
else
    printf '%s\n' 'No line was read before the wait ended; continuing.'
fi

若要讓使用者選擇整數秒數,先將輸入讀入變數,再把加上引號的值傳給 sleep。以下範例會在呼叫 sleep 前檢查輸入是否為不超過三位數的數字;若沒有合適的一行輸入,也會顯示提示:

#!/usr/bin/env bash
if read -r -p 'Enter a whole number of seconds (up to 3 digits): ' duration \
    && [[ $duration =~ ^[0-9]{1,3}$ ]]; then
    sleep "$duration"
    printf 'Requested a %s-second wait.\n' "$duration"
else
    printf '%s\n' 'Enter a whole number with at most 3 digits.'
fi

這項檢查會先驗證輸入,再將值交給 sleep,避免把格式錯誤的文字當作等待時間傳入。若指令碼需要不同的限制,可以調整允許的範圍,並向使用者說明限制。

簡而言之,使用 sleep 進行定時的整數秒延遲,使用 read 等待輸入。Bash 的 read -t 則結合兩者:收到一行輸入或逾時後,等待便會結束。