use*_*909 70 command-line bash process background-process process-groups
我想在单个 shell 上运行多个命令(进程)。都有自己的连续输出,不停歇。在后台运行它们Ctrl- C。我想将它们作为单个进程(子shell,也许?)运行,以便能够用Ctrl-停止所有这些进程C。
具体来说,我想使用mocha(监视模式)运行单元测试,运行服务器并运行一些文件预处理(监视模式),并在一个终端窗口中查看每个测试的输出。基本上我想避免使用一些任务运行器。
我可以通过在后台运行进程 ( &)来实现它,但是我必须将它们放到前台来阻止它们。我想要一个包装它们的过程,当我停止这个过程时,它会停止它的“孩子”。
Min*_*nix 83
要同时运行命令,您可以使用&命令分隔符。
~$ command1 & command2 & command3
Run Code Online (Sandbox Code Playgroud)
这将启动command1,然后在后台运行它。与 相同command2。然后它command3正常启动。
所有命令的输出都会乱码,但如果这对您来说不是问题,那就是解决方案。
如果您想稍后单独查看输出,您可以将每个命令的输出通过管道tee传输到 中,这样您就可以指定将输出镜像到的文件。
~$ command1 | tee 1.log & command2 | tee 2.log & command3 | tee 3.log
Run Code Online (Sandbox Code Playgroud)
输出可能会非常混乱。为了解决这个问题,您可以使用sed.
~$ echo 'Output of command 1' | sed -e 's/^/[Command1] /'
[Command1] Output of command 1
Run Code Online (Sandbox Code Playgroud)
因此,如果我们将所有这些放在一起,我们会得到:
~$ 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
Run Code Online (Sandbox Code Playgroud)
这是您可能会看到的高度理想化的版本。但它是我现在能想到的最好的。
如果你想一次停止所有这些,你可以使用trap.
~$ trap 'kill %1; kill %2' SIGINT
~$ command1 & command2 & command3
Run Code Online (Sandbox Code Playgroud)
这将执行command1,并command2在后台command3在前台,它可以让你杀了它Ctrl+ C。
当你用Ctrl+杀死最后一个进程时C,kill %1; kill %2命令会被执行,因为我们将它们的执行与一个 INTerupt 信号的接收联系起来,这个信号是通过按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] /'
Run Code Online (Sandbox Code Playgroud)
当然,你可以看看screen。它可以让您根据需要将控制台拆分为多个单独的控制台。因此,您可以分别监视所有命令,但同时监视。
Gil*_*il' 30
如果您安排在同一进程组中运行它们(并且仅运行它们),您可以轻松地一次杀死一堆进程。
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"
Run Code Online (Sandbox Code Playgroud)
如果您从非交互式shell在后台运行进程,那么它们都将保留在 shell 的进程组中。只有在交互式 shell 中,后台进程才能在它们自己的进程组中运行。因此,如果您从保留在前台的非交互式 shell 中分叉命令,Ctrl+C将杀死它们。使用wait内置命令让 shell 等待所有命令退出。
sh -c 'command1 & command2 & command3 & wait'
# Press Ctrl+C to kill them all
Run Code Online (Sandbox Code Playgroud)
小智 25
我很惊讶这还不在这里,但我最喜欢的方法是使用带有后台命令的子shell。用法:
(command1 & command2 & command3)
两者都可以看到输出,所有 bash 命令和便利工具仍然可用,一个就可以Ctrl-c杀死它们。我通常使用它同时启动实时调试客户端文件服务器和后端服务器,因此我可以在需要时轻松杀死它们。
其工作原理是,command1和command2在一个新的子shell实例的后台运行,并command3在该实例的前景,以及子shell是什么第一次收到一个杀信号Ctrl-c按键。关于谁拥有什么进程以及后台程序何时被杀死,这非常类似于运行 bash 脚本。