我想在一个 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
前台执行,这让你可以用+杀死它。 command2
command3
CtrlC
Ctrl当您使用+杀死最后一个进程时,C命令kill %1; kill %2
将被执行,因为我们将它们的执行与中断信号的接收连接起来,中断信号是通过按Ctrl+发送的C。
他们分别杀死第一个和第二个后台进程(您的command1
和command2
)。使用完命令后,不要忘记删除陷阱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可以将它们全部杀死。我通常使用它来同时启动实时调试客户端文件服务器和后端服务器,这样我就可以在需要时轻松杀死它们。
它的工作方式是,command1
和command2
正在新的子 shell 实例的后台运行,并且command3
位于该实例的前台,并且子 shell 是首先接收来自Ctrl-c按键的终止信号的。关于谁拥有哪个进程以及后台程序何时被终止,这非常类似于运行 bash 脚本。
答案4
您可以使用一个pipe
.这将同时启动管道两端的命令。您应该也可以使用 来停止所有命令CTRL-C
。
1st command | 2nd command | 3rd command
如果你想一个接一个地运行命令,你可以使用@serenesat的方法。