Bash 原生不支援多執行緒,但可利用「具名管道 (FIFO) + read -u 信號量」模擬固定並發數的工作池。本文提供生產級範本,適用於 SSH 批次巡檢、Ping 掃描、API 並發請求等 I/O 密集型任務。
mkfifo /tmp/$$.fifo。exec 6<>/tmp/$$.fifo。N 個換行符 (Token),代表可用並發槽位。read -u6 取走一個 Token (槽位滿則阻塞)。echo >&6 歸還 Token。wait 等待所有背景子任務完成。parallel.sh#!/bin/bash
# 使用方式: parallel.sh 並發數 任務清單檔
# 任務清單: 每行一個參數 (如 IP、URL、主機名)
set -euo pipefail
MAX_JOBS=${1:-10}
TASK_FILE=${2:-/dev/stdin}
TMP_FIFO="/tmp/$$.fifo"
mkfifo "$TMP_FIFO"
exec 6<>"$TMP_FIFO"
rm -f "$TMP_FIFO"
# 初始化 Token 池
for ((i=0; i&6
done
task_func() {
local arg=$1
# ===== 在此處實作實際任務 =====
# 範例: ssh 檢查
ssh -o ConnectTimeout=5 -o BatchMode=yes "$arg" "hostname && uptime"
# ================================
}
# 讀取任務清單並發派
while IFS= read -r arg; do
[[ -z "$arg" ]] && continue
read -u6 # 取 Token (阻塞直到有空槽)
{
task_func "$arg"
echo >&6 # 歸還 Token
} &
done < "$TASK_FILE"
wait # 等待所有背景任務
exec 6>&- # 關閉 FD 6
echo "所有任務完成"
# 1. 建立目標清單
cat > hosts.txt <
timeout 30 task_func "$arg" 防止卡死。task_func 內部實作重試邏輯或回傳碼判斷。echo -ne "Progress: $done/$total\r"。| 工具 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| GNU Parallel | 功能豐富、自動分發、進度條、保序 | 需額外安裝、語法複雜 | 通用並發、跨機器 |
| xargs -P | 內建、簡單 | 無法控制啟動頻率、難處理複雜邏輯 | 簡單命令並發 |
| FIFO + read (本文) | 純 Bash、無依賴、精確控制並發、易嵌入腳本 | 需理解 FD/FIFO、錯誤處理需自行實作 | 嵌入式/最小環境、自訂邏輯 |
| Python multiprocessing / asyncio | 真多執行緒/協程、豐富生態 | 需 Python 環境、啟動較重 | 複雜運算/高併發 |
exec 6<>fifo 必須雙向開啟,單向 6< 或 6> 會導致寫入/讀取阻塞。read 或 ssh 等消耗 stdin,需加 </dev/null 或重導向,避免搶佔主迴圈 stdin。掌握 FIFO 信號量模式,即可在純 Shell 腳本中實現穩定可控的並發處理,無需額外依賴。