如何从bash脚本中并行运行多个程序?
如何在Bash脚本中并行运行多个程序?
如果你想要能够轻松地运行和终止多个进程,并且使用ctrl-c
,这是我最喜欢的方法:在一个(...)
子shell中生成多个后台进程,并捕获SIGINT
信号执行kill 0
命令,它将终止子shell组中的所有进程:
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3)
你可以创建复杂的进程执行结构,一切都将在单个ctrl-c
下关闭(只需确保最后一个进程在前台运行,即prog1.3
后面不要加&
):
(trap 'kill 0' SIGINT; prog1.1 && prog1.2 & (prog2.1 | prog2.2 || prog2.3) & prog1.3)
如果最后一个命令可能会提前退出,并且你希望保持其他所有进程继续运行,请将wait
作为最后一个命令添加。在下面的示例中,sleep 2
会先退出,导致在它完成之前终止sleep 4
;添加wait
命令可以使两者都运行完成:
(trap 'kill 0' SIGINT; sleep 4 & sleep 2 & wait)
这是迄今为止最好的答案。
kill 0
是什么意思?它是指子shell本身的PID 0吗?
是的,kill
命令将0
解释为“当前进程组中的所有进程都被发送信号”。man页面中包含了这个描述。
太棒了,运行得很好。这是一个很好的示例,说明了子shell的用途。
我必须使用trap 'kill 0' INT;
代替SIGINT
我使用了(trap 'kill 0' SIGINT EXIT; blabla)
,因为它更可靠(当错误发生时终止所有守护进程)。
谢谢!提醒一下:我需要为每个命令的输出使用grep
,所以我发现可以简单地使用(trap 'kill 0' SIGINT; prog1 & prog2) | grep XXX
而不是(trap 'kill 0' SIGINT; (prog1 | grep XXX) & (prog2 | grep XXX))
。
只有在最后一个命令(前台命令)也是最后退出时,才有效。否则整个过程会过早退出。
(trap 'kill 0' SIGINT; prog1 & prog2 & prog3 & wait)
可以确保所有程序都完成。
这在WSL2上实际可行!
Ingo Bürk的评论似乎是正确的。例如,(trap 'kill 0' SIGINT; (sleep 4; echo Hello) & (sleep 2 ; echo World))
的结果是:等待两秒钟,打印"World",剩余的进程在后台(即,你又有了一个活动的Shell提示符),然后再等待两秒钟,打印"Hello"。
我已经更新了答案,建议使用wait
作为最后一个命令。感谢Ingo Bürk、orion elenzil和jakeonfire的建议。
这是一个很好的答案,但我建议将更新后的wait
版本放在前面,并将其作为主要解决方案。99%的情况下,用户都会期望这样的结果。
如何在bash脚本中并行运行多个程序?
要并行运行多个程序,可以使用以下命令:
prog1 & prog2 &
如果需要脚本等待这些程序运行结束,可以在需要等待的位置添加以下命令:
wait
不要忘记使用wait
命令!在bash中,可以等待脚本的子进程。
另一个选项是使用nohup
命令,防止程序在shell挂断时被终止。
是的,这种方法也适用于并行运行三个或更多个程序。
也许是一个愚蠢的问题,但如果我想运行prog1 | something & prog2 | another &
,会发生什么?我相信这不会起作用。
它完全可以正常工作;为什么你认为它不会起作用?
有没有办法只列出从当前bash终端创建/运行的进程?
这个问题可能值得提问,但简短的回答是你可以运行jobs
命令来查看从当前shell放入后台的进程。
当prog1不返回光标控制权时,也就是在一个终端上一个程序占用了,所以prog2将需要一个新的终端,这种情况怎么办?
我不确定你的意思。显然,在同一个终端中不能同时运行多个需要完全控制终端的程序 - 但这不是问题的要求 - 它询问的是如何从同一个脚本中同时运行大量程序 🙂
prog1
和prog2
都在后台运行吗?
如果它们两个后面都有&
,那么是的,它们都在后台运行。
如果有人能展示一下如何使用wait命令以及同时运行的prog1和prog2,那将很棒。不是交互式的,可以通过许多更简单的方式来实现,比如只运行第二个终端...我想wait命令可以神奇地跟踪脚本中所有正在后台运行的进程?如何确保如果其中一个程序以!= 0退出,我的脚本会终止?
问题的出现原因:在bash脚本中如何同时运行多个程序。
解决方法:使用以下命令:
prog1 & prog2 && fg
这将实现以下功能:
1. 启动prog1
。
2. 将prog1
发送到后台,但保持输出。
3. 启动prog2
,并将其保持在前台,以便可以使用ctrl-c
关闭。
4. 当关闭prog2
时,会返回到prog1
的前台,以便也可以使用ctrl-c
关闭。
如果想要在prog2
终止时轻松终止prog1
,可以尝试以下命令:node srv.js & cucumberjs
。
也可以尝试稍作修改:prog1 & prog2 ; fg
。这适用于同时运行多个SSH隧道。
如果希望在prog2
无法立即运行时,自动返回到prog1
的前台,那么上述方法是可行的。
在SSH的shell中,如果执行类似命令,将很难终止prog1
。即使按下ctrl-c
,也不起作用。即使终止整个终端,prog1
仍然在运行。
一种同时终止两个进程的方法是:prog1 & prog2 && kill $!
。
可以使用以下命令一次停止两个命令:prog1 & pid1="$!" ; prog2 ; kill $pid1
。
这对我起作用。在第一次按下ctrl-c
后,prog1
将回到前台:prog1 & prog2 && fg; fg
。
需要注意的是,在shell脚本中不能使用fg
命令。会显示"fg: no job control"。这是因为脚本不是交互式的shell。