如何在Bash中并行运行满足特定要求的长期进程?
如何管理多个长期运行进程:一键启停+故障联动终止
我太懂你的痛点了——要同时跑几个不会自己终止的服务,得实时盯着输出,一个挂了所有进程都得停,手动按Ctrl+C也得把所有进程都干掉。&加wait确实搞不定信号处理的问题,GNU Parallel其实没你想的那么复杂,我给你两个实打实的方案:
方案一:用Bash脚本手动管控(最灵活)
写个简单的脚本就能完全满足需求,比如叫run_services.sh:
#!/bin/bash # 把你要运行的进程都列在这里 PROCESSES=( "python3 my_long_running_app1.py" "node server.js" "./my_custom_daemon" ) # 存所有子进程的PID PIDS=() # 捕获Ctrl+C(INT)和终止信号(TERM),收到就杀所有子进程 trap 'echo "收到终止信号,正在停止所有进程..."; kill "${PIDS[@]}" 2>/dev/null; exit 0' INT TERM # 逐个启动进程,记录PID for cmd in "${PROCESSES[@]}"; do echo "启动进程: $cmd" # setsid让进程在新会话运行,避免输出混乱,也能保证输出正常打到终端 setsid $cmd & PIDS+=($!) done # 循环监控所有进程,一个挂了就全杀 while true; do for pid in "${PIDS[@]}"; do # 检查进程是否存活(kill -0不发信号,只检查存在性) if ! kill -0 "$pid" 2>/dev/null; then echo "进程PID $pid 已退出,正在终止所有其他进程..." kill "${PIDS[@]}" 2>/dev/null exit 1 fi done sleep 1 done
脚本关键点说明:
trap命令帮你处理手动中断(Ctrl+C)和外部终止信号,确保所有子进程都能被清理setsid可以避免多个进程的输出互相乱跳,也能防止子进程因为脚本的终端问题意外退出- 监控循环每秒检查一次进程状态,只要有一个进程退出,立刻触发全量终止
- 运行时直接
chmod +x run_services.sh && ./run_services.sh,所有输出都会显示在终端,按Ctrl+C就能一键停所有
方案二:用GNU Parallel快速实现(不用写脚本)
GNU Parallel的--halt now,fail=1参数正好命中你的需求:只要有一个任务退出(不管退出码是什么),立刻终止所有其他任务,而且默认会把所有任务的输出合并到终端显示。
基础用法:
parallel --halt now,fail=1 ::: \ "python3 my_long_running_app1.py" \ "node server.js" \ "./my_custom_daemon"
参数解释:
--halt now,fail=1:核心参数,意思是立刻停止所有任务,只要有1个任务退出(失败)::::用来分隔你要运行的命令列表- 按Ctrl+C时,Parallel会自动清理所有子进程,完全符合你的要求
进阶:给输出加标识
如果想区分哪个进程的输出,可以加--tag参数,每个输出行前会带上对应的命令:
parallel --tag --halt now,fail=1 ::: \ "python3 my_long_running_app1.py" \ "node server.js" \ "./my_custom_daemon"
额外提示
- 如果你用的是zsh,方案一的脚本只需要把
#!/bin/bash改成#!/bin/zsh就能正常运行 - 方案一中如果不想用
setsid,直接$cmd &也可以,但偶尔会出现输出乱序的情况,setsid能优化这个问题
内容的提问来源于stack exchange,提问作者enumag




