运行多个命令并在 bash 中将它们作为一个命令杀死

运行多个命令并在 bash 中将它们作为一个命令杀死

我想在一个 shell 上运行多个命令(进程)。它们都有自己的持续输出,不会停止。在后台运行它们会中断Ctrl- C。我想将它们作为单个进程(也许是子shell?)运行,以便能够使用Ctrl-停止所有这些进程C

具体来说,我想使用mocha(监视模式)运行单元测试,运行服务器并运行一些文件预处理(监视模式),并在一个终端窗口中查看每个测试的输出。基本上我想避免使用一些任务运行程序。

我可以通过在后台运行进程来实现它(&),但随后我必须将它们放入前台来停止它们。我想要一个进程来包装它们,当我停止该进程时,它会停止它的“子进程”。

答案1

要同时运行命令,您可以使用&命令分隔符。

~$ command1 & command2 & command3

这将启动command1,然后在后台运行。与 相同command2。然后就可以正常启动了command3

所有命令的输出都会乱码在一起,但如果这对您来说不是问题,那么这就是解决方案。

如果您想稍后单独查看输出,可以将每个命令的输出通过管道传输到tee,这样您就可以指定将输出镜像到的文件。

~$ command1 | tee 1.log & command2 | tee 2.log & command3 | tee 3.log

输出可能会非常混乱。为了解决这个问题,您可以使用 给每个命令的输出一个前缀sed

~$ echo 'Output of command 1' | sed -e 's/^/[Command1] /' 
[Command1] Output of command 1

因此,如果我们将所有这些放在一起,我们会得到:

~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'
[Command1] Starting command1
[Command2] Starting command2
[Command1] Finished
[Command3] Starting command3

这是您可能会看到的高度理想化的版本。但这是我现在能想到的最好的。

如果您想立即停止所有这些,您可以使用 中的构建trap

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 & command2 & command3

这将在后台和command1前台执行,这让你可以用+杀死它。 command2command3CtrlC

Ctrl当您使用+杀死最后一个进程时,C命令kill %1; kill %2将被执行,因为我们将它们的执行与中断信号的接收连接起来,中断信号是通过按Ctrl+发送的C

他们分别杀死第一个和第二个后台进程(您的command1command2)。使用完命令后,不要忘记删除陷阱trap - SIGINT

完成怪物的命令:

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'

当然,你可以看看屏幕。它可以让您根据需要将控制台拆分为多个单独的控制台。因此您可以同时单独监视所有命令。

答案2

如果你安排在同一个进程中运行它们(并且仅运行它们),你可以轻松地一次杀死一堆进程。进程组

Linux 提供了实用程序setsid在新的进程组中运行程序(甚至在新的会话中,但我们不关心这一点)。 (这是可行但更复杂没有setsid。)

进程组的进程组ID(PGID)是组中原始父进程的进程ID。要终止进程组中的所有进程,请将 PGID 的负数传递给kill系统调用或命令。即使具有该 PID 的原始进程终止,PGID 仍然有效(尽管这可能有点令人困惑)。

setsid sh -c 'command1 & command2 & command3' &
pgid=$!
echo "Background tasks are running in process group $pgid, kill with kill -TERM -$pgid"

如果您在后台运行进程非交互式shell,那么它们都将保留在shell的进程组中。只有在交互式 shell 中,后台进程才会在自己的进程组中运行。因此,如果您从保留在前台的非交互式 shell 中分叉命令,Ctrl+C将杀死所有命令。使用wait内置命令让 shell 等待所有命令退出。

sh -c 'command1 & command2 & command3 & wait'
# Press Ctrl+C to kill them all

答案3

我很惊讶它还没有出现,但我最喜欢的方式是使用子壳层与后台命令。用法:

(command1 & command2 & command3)

两者的输出都是可见的,所有 bash 命令和便利仍然可用,并且单个命令Ctrl-c可以将它们全部杀死。我通常使用它来同时启动实时调试客户端文件服务器和后端服务器,这样我就可以在需要时轻松杀死它们。

它的工作方式是,command1command2正在新的子 shell 实例的后台运行,并且command3位于该实例的前台,并且子 shell 是首先接收来自Ctrl-c按键的终止信号的。关于谁拥有哪个进程以及后台程序何时被终止,这非常类似于运行 bash 脚本。

答案4

您可以使用一个pipe.这将同时启动管道两端的命令。您应该也可以使用 来停止所有命令CTRL-C

1st command | 2nd command | 3rd command

如果你想一个接一个地运行命令,你可以使用@serenesat的方法。

相关内容