You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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

火山引擎 最新活动