进程完成后运行 bash 命令

emr*_*rah 11 bash shell-script

我有两个使用 GPU 和训练 ML 模型的脚本。我想在睡觉前启动它们,这样它们就可以在晚上工作,我希望在早上看到一些结果。

但是由于 GPU 内存有限,我想串行而不是并行运行它们。

我可以做到python train_v1.py && python train_v2.py;但假设我开始训练train_v1. 同时,由于训练时间较长,我开始并完成了第二个脚本的实现train_v2.py,我想在python train_v1.py完成时自动运行它。

我怎样才能做到这一点?谢谢你。

JoL*_*JoL 29

这是一种方法,它不涉及循环和检查另一个进程是否还活着,或者train_v1.py以与您通常所做的不同的方式调用:

$ python train_v1.py
^Z
[1]+  Stopped                 python train_v1.py
$ % && python train_v2.py
Run Code Online (Sandbox Code Playgroud)

^Z是我按下Ctrl+ Z,而正在运行的进程睡眠train_v1.py通过发送一个SIGTSTP信号。然后,我告诉 shell 用 唤醒它%,使用它作为我可以&& python train_v2.py在最后添加的命令。这使得它的行为就像你python train_v1.py && python train_v2.py从一开始就做的一样。

取而代之的是%,您还可以使用fg. 这是同一件事。如果您想了解有关 shell 的这些类型功能的更多信息,可以在bash 联机帮助页的“作业控制”部分中阅读有关它们的信息

编辑:如何继续添加到队列

正如 jamesdlin 在评论中指出的那样,如果您尝试train_v3.py在 v2 启动之前继续添加模式,您会发现您不能:

$ % && python train_v2.py
^Z
[1]+  Stopped                 python train_v1.py
Run Code Online (Sandbox Code Playgroud)

只会train_v1.py因为train_v2.py尚未开始而停止,并且您无法停止/暂停/睡眠甚至尚未开始的东西。

$ % && python train_v3.py
Run Code Online (Sandbox Code Playgroud)

将导致相同

python train_v1.py && python train_v3.py
Run Code Online (Sandbox Code Playgroud)

因为%对应于最后一个挂起的进程。与其尝试这样添加v3,不如使用历史记录:

$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py
Run Code Online (Sandbox Code Playgroud)

可以像上面那样进行历史扩展,或者使用键绑定(如 up)调用最后一个命令并将 v3 添加到最后。

$ % && python train_v2.py && python train_v3.py
Run Code Online (Sandbox Code Playgroud)

这是可以重复的东西,以向管道添加更多内容。

$ !! && python train_v3.py
% && python train_v2.py && python train_v3.py
^Z
[1]+  Stopped                 python train_v1.py
$ !! && python train_v4.py
% && python train_v2.py && python train_v3.py && python train_v4.py
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一可靠的解决方案,也是最容易启动的解决方案。 (4认同)

Kus*_*nda 11

如果您已经开始python train_v1.py,您可能会使用pgrep轮询该进程直到它消失,然后运行您的第二个 Python 脚本:

while pgrep -u "$USER" -fx 'python train_v1.py' >/dev/null
do
    # sleep for a minute
    sleep 60
done
python train_v2.py
Run Code Online (Sandbox Code Playgroud)

通过使用-fand-x匹配用于启动第一个 Python 脚本的确切命令行。在某些系统上,pgrep实现一个-q选项,使其安静(就像grep -q),这意味着/dev/null不需要重定向到。

-u选项将匹配限制为您正在运行的命令(而不是同一系统上的朋友或其他人)。

如果你还没有开始第一个脚本:

正如评论中提到的,您可以在第一个脚本之后直接启动第二个脚本。第二个脚本不存在或尚未准备好运行的事实并不重要(只要它准备好在第一个脚本完成时运行):

python train_v1.py; python train_v2.py
Run Code Online (Sandbox Code Playgroud)

无论第一个脚本的退出状态如何,这样做都会启动第二个脚本。使用&&而不是;,正如您在问题中所示,也可以工作,但需要第一个脚本成功完成才能启动第二个脚本。

  • 我更喜欢运行一次 `ps` 来找出第一个脚本的 pid,然后运行像 `while kill -0 <pid>` 这样的循环。是否经常发生`pgrep`(或`killall`)发现了不想要的东西,尤其是在多用户系统上。顺便说一句,`kill -0` 不会对被杀死的进程做任何事情,它只是检查该进程是否仍然存在。 (4认同)
  • @GuntramBlohmsupportsMonica 您显然可以在多用户系统上使用 `pgrep -u "$USER" ...`。使用 `pgrep` 还可以避免在频繁使用的系统上重复使用 PID 引起的问题。 (4认同)

Qua*_*odo 6

您可以启动第一个脚本

python train_v1.py; touch finished
Run Code Online (Sandbox Code Playgroud)

然后简单地创建一个循环,定期检查是否finished存在:

while [ ! -f finished ] ; do     
    sleep 5
done
python train_v2.py
rm finished
Run Code Online (Sandbox Code Playgroud)

  • 与`python train_v1.py 相比的优势在哪里?python train_v2.py`? (4认同)
  • @GuntramBlohmsupportsMonica 我想说它更具可定制性,最重要的是,您无需费心事先选择第二个程序。抛开这些考虑,没有任何优势。 (2认同)