& 启动后台任务必须配合 wait 才能可靠收尾,否则子进程易成孤儿、变量不回传、输出乱序且无法捕获各任务退出码;需用 wait $pid 或 wait -n 获取状态,并结合 jobs -r 动态限流。

直接用 & 启动后台任务 + wait 同步是最轻量、最可控的方式,不需要额外工具,也避免了 xargs -P 对输入格式的苛刻要求和 GNU Parallel 的依赖问题。
为什么不能只写 cmd & 就完事
单独加 & 确实能并发,但极易踩坑:脚本主线程不等子进程就退出,导致子进程变成孤儿;变量在子 shell 中修改不回传;输出乱序且无法捕获每个任务的退出码。比如:
-
for i in {1..5}; do echo $i >> log; done→ 串行,log 是 1 2 3 4 5 -
for i in {1..5}; do echo $i >> log & done→ 并发,但 log 可能是 31524 或部分缺失,且没等完就继续执行后续命令
关键不是“能不能并发”,而是“能不能可靠收尾”。必须配 wait,否则等于没控。
wait 怎么用才不丢状态
wait 本身不保存退出码,$? 只反映上一个命令的结果,所以必须在 wait 后立刻读取对应 PID 的状态——而且得用 wait -n 或显式等待指定 PID。
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
- 启动时存 PID:
cmd & pid=$! - 等单个任务并取状态:
wait $pid; echo "exit: $?" - 等任意一个完成(用于限流):
wait -n,配合jobs -r | wc -l判断当前并发数 - 别用无参
wait后再查$?——它返回的是最后那个结束进程的状态,其他全丢了
如何限制最大并发数不打爆系统
不限制并发数等于赌运气。50 个 ping 同时发出去,可能触发 ICMP flood 限速或耗尽文件描述符。正确做法是动态控流:
- 每次提交新任务前,检查当前后台任务数:
jobs -r | wc -l - 超过阈值就
wait -n等一个空位释放 - 示例逻辑:
MAX=3 for task in "${tasks[@]}"; do while [ $(jobs -r | wc -l) -ge $MAX ]; do wait -n; done run_task "$task" & done wait - 注意:
jobs -r只显示运行中任务,比ps更轻量,且不依赖外部命令
xargs -P 和 & + wait 选哪个
看输入来源和控制粒度:
- 用
xargs -P:输入是纯文本流(如find结果)、命令完全一致、不关心单个失败、不怕空格换行(记得加-print0 | xargs -0) - 用
& + wait:要为每个任务设不同参数、需捕获各自退出码、要重定向各自日志、要动态判断是否重试、要处理含空格/换行的变量(比如数组元素) - 别混用:比如
echo "${arr[@]}" | xargs -P 4 ...在数组含空格时会崩,而for item in "${arr[@]}"; do ... & done天然安全
真正容易被忽略的是子 shell 变量隔离——在 (...) 或后台任务里改的变量,父脚本完全看不见;需要结果必须通过文件、命名管道或 wait 后解析输出来传递。

















