如何运用Bash的作业控制来管理前台和后台进程

在本指南中,我们将讨论bash中,Linux系统,你的终端是如何走到一起,提供流程和作业控制。在前面的指南中,我们讨论了如何...

介绍

在本指南中,我们将讨论如何bash ,Linux系统和终端走到一起,提供流程和作业控制。 先前的指导 ,我们讨论了如何pskill ,和nice命令可以用来控制你的系统中的进程。

本文将重点介绍管理前台和后台进程,并将演示如何利用shell的作业控制功能来获得更多的运行命令的灵活性。

管理前台进程

在Linux机器上启动的大多数进程将在前台运行。 命令将开始执行,阻止在进程的持续时间使用shell。 该过程可以允许用户交互,或者可以仅运行过程,然后退出。 默认情况下,任何输出将显示在终端窗口中。 我们将在下面讨论管理前台进程的基本方法。

启动进程

默认情况下,进程在前台启动。 直到程序退出或更改状态,您将无法与shell进行交互。

一些前台命令很快退出,并立即返回到shell提示符。 例如,此命令:

echo "Hello World"

这将打印“Hello World”到终端,然后返回到您的命令提示符。

其他前台命令需要更长的时间才能执行,阻止shell访问持续时间。 这可能是因为命令正在执行更广泛的操作,或者因为它被配置为运行,直到它被显式停止或直到它接收到其他用户输入。

运行无限期的命令是top工具。 启动后,它将继续运行和更新其显示,直到用户终止进程:

top

您可以通过键入“q”退出。 一些进程没有专用的退出功能。 要停止这些,你必须使用另一种方法。

终止进程

假设我们开始了一个简单bash命令行上循环。 我们可以开始一个循环,每10秒打印一次“Hello World”。 这个循环将永远持续,直到显式终止:

while true; do echo "Hello World"; sleep 10; done

循环没有“退出”键。 我们将通过发送一个信号 ,停止进程。 在Linux中,内核可以发送进程信号,以请求退出或更改状态。 Linux的终端通常被配置的时候了“SIGINT”发送信号(通常为数字信号2)当前的前台进程CTRL-C按下组合键。 SIGINT信号通知程序用户已使用键盘请求终止。

要停止我们开始的循环,按住控制键,然后按“c”键:

CTRL-C

循环将退出,将控制权返回到shell。

由发送SIGINT信号CTRL-C组合是可以被发送到节目许多信号中的一个。 大多数的信号没有与它们相关的键盘组合,必须使用被送到kill的命令,而不是(我们将讨论这个版本)。

暂停进程

我们上面提到,前台进程将在执行期间阻止对shell的访问。 如果我们在前台启动一个进程,但是后来意识到我们需要访问终端呢?

我们可以发送的另一个信号是“SIGTSTP”信号(通常是信号号20)。 当我们打CTRL-Z我们的终端注册到“暂停”命令,然后发送SIGTSTP信号发送到前台进程。 这将基本上暂停命令的执行并将控制返回到终端。

为了演示,让我们使用ping连接到google.com每5秒。 我们将先于ping带命令command ,这将使我们能够绕过人为设定的命令最大计数任何shell别名:

command ping -i 5 google.com

相反,终止与该命令CTRL-C键入CTRL-Z来代替:

CTRL-Z

您将看到如下所示的输出:

[1]+  Stopped                 ping -i 5 google.com

ping的命令已被暂时停止,让您再次进入到命令提示符。 我们可以用ps处理工具来显示这一点:

ps T
  PID TTY      STAT   TIME COMMAND
26904 pts/3    Ss     0:00 /bin/bash
29633 pts/3    T      0:00 ping -i 5 google.com
29643 pts/3    R+     0:00 ps t

我们可以看到, ping过程仍在上市,但该“STAT”栏目中有一个“T”。 ps手册页告诉我们,这表示已“由(一)作业控制信号,停止”的工作。

我们将更深入地讨论如何改变过程状态,但是现在,我们可以通过键入以下命令来恢复前台命令的执行:

fg

一旦这个过程已经恢复,以终止CTRL-C

CTRL-C

管理后台进程

在前台运行进程的主要替代方法是允许它在后台执行。 后台进程与启动它的特定终端相关联,但不会阻止对shell的访问。 相反,它在后台执行,让用户能够在命令运行时与系统交互。

由于前台进程与其终端交互的方式,每个终端窗口只能有一个前台进程。 因为后台进程立即将控制返回到shell,而不等待进程完成,许多后台进程可以同时运行。

启动进程

您可以通过在命令末尾附加一个&符号(“&”)来启动一个后台进程。 这告诉shell不要等待进程完成,而是开始执行并立即将用户返回到提示符。 命令的输出仍然将在终端(除非显示重定向 ),但作为背景过程继续可以键入附加命令。

例如,我们可以从后台的最后一部分开始相同的ping过程:

command ping -i 5 google.com &

你会看到从输出bash作业控制系统,看起来像这样:

[1] 4287

您还将看到从正常输出ping命令:

PING google.com (74.125.226.71) 56(84) bytes of data.
64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=1 ttl=55 time=12.3 ms
64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=2 ttl=55 time=11.1 ms
64 bytes from lga15s44-in-f7.1e100.net (74.125.226.71): icmp_seq=3 ttl=55 time=9.98 ms

但是,您也可以同时键入命令。 后台进程的输出将在前台进程的输入和输出之间混合,但不会干扰前台进程的执行。

列出后台进程

要查看所有已停止或后台运行的进程,您可以使用jobs命令:

jobs

如果你有ping在后台运行命令,你会看到类似下面这样:

[1]+  Running                 command ping -i 5 google.com &

这表明我们当前有一个后台进程运行。 [1]表示命令的“工作规范”和工号。 我们可以与其他的工作和过程控制指令引用此,像killfgbg作业号与百分号之前。 在这种情况下,我们会参考这个工作作为%1

停止后台进程

我们可以通过几种方式停止当前的后台进程。 最直接的方式是使用kill命令和大专职位数。 例如,我们可以通过键入以下命令来杀死我们的运行后台进程:

kill %1

根据终端的配置,立即或下次按ENTER键时,您将看到作业终止状态:

[1]+  Terminated              command ping -i 5 google.com

如果我们检查jobs再次命令,我们将看不到当前作业。

改变过程状态

现在我们知道如何在后台启动和停止进程,我们可以谈论如何改变它们的状态。

我们证明,当我们描述了如何停止或暂停使用过程中的一个状态改变先前CTRL-Z 当进程处于此停止状态时,我们可以将前台进程移动到后台,反之亦然。

将前台进程移动到后台

如果我们忘记了,以结束与命令&当我们开始吧,我们仍然可以在移动过程中的背景。

第一步是停止与过程CTRL-Z再次:

CTRL-Z

一旦这个过程被停止,我们可以使用bg命令在后台再次启动:

bg

您将再次看到作业状态行,此时带有&符号:

[1]+ ping -i 5 google.com &

默认情况下, bg命令对最近停止的进程运行。 如果您已连续停止多个进程,但未重新启动它们,则可以按作业编号引用该进程,以使正确的进程背景。

请注意,并非所有命令都可以作为背景。 如果某些进程检测到它们的标准输入和输出直接连接到活动终端,则这些进程将自动终止。

将后台进程移动到前台

我们也可以通过键入移动后台进程的前景fg

fg

这个运行在您最近背景程序(在用“+”表示jobs输出)。 它立即暂停进程并将其放入前台。 要指定其他作业,请使用其作业编号:

fg %2

一旦一个工作是在前台,你可以杀了它CTRL-C让它完整,或再次暂停和背景的。

处理SIGHUP

无论进程是在后台还是在前台,它都与启动它的终端实例紧密绑定。 当终端关闭时,它通常向绑定到终端的所有进程(前台,后台或停止)发送SIGHUP信号。 这表示进程终止,因为它们的控制终端将很快不可用。 如果要关闭终端但保持后台进程运行会怎么样?

有许多方法来实现这一点。 最灵活的方式通常是使用一个终端复用器像screentmux ,或使用一个实用程序,提供至少那些的分离功能,比如dtach

然而,这并不总是一个选择。 有时这些程序不可用,或者您已经开始了继续运行所需的过程。 有时候,这些是对你需要完成的过度杀伤。

使用nohup

如果你知道开始,你将要在该过程完成之前关闭终端的进程时,可以使用启动它nohup命令。 这使得启动的进程免受SIGHUP信号的干扰。 当终端关闭时,它将继续运行。 它将被重新分配为init系统的子代:

nohup ping -i 5 google.com &

你会看到一条线,看起来像这样,表明该命令的输出将被写入到一个名为nohup.out (在当前目录,如果写的,否则你的home目录):

nohup: ignoring input and appending output to ‘nohup.out’

这是为了确保如果终端窗口关闭,输出不会丢失。

如果关闭终端窗口并打开另一个终端窗口,该过程仍将运行。 你不会看到它的输出jobs命令,因为每个终端实例维护它自己独立的作业队列。 终端闭导致ping 的工作被破坏,即使ping 进程仍在运行。

ping过程中,你要查找它的进程ID(或“PID”)。 你可以做到这一点的pgrep命令(也有pkill命令,但是这两个部分的方法,确保我们只杀预期的过程)。 使用pgrep-a标志搜索可执行文件:

pgrep -a ping
7360 ping -i 5 google.com

然后可以通过引用返回的PID来终止进程,这是第一列中的数字:

kill 7360

您可能希望删除nohup.out文件,如果你不需要它了。

使用不存在

nohup命令是有帮助的,但是只有当你知道你会需要它在启动过程的时间。 bash作业控制系统提供了实现的结果相似的其他方法disown建命令。

disown命令,在其默认的配置,删除从终端的工作队列中的作业。 这意味着它不能再使用本指南中讨论的作业控制机制进行管理(如fgbgCTRL-Z CTRL-C 它将立即被从列表中删除jobs输出和不再与终端相关联。

通过指定作业号来调用该命令。 例如,要立即删除作业2,我们可以键入:

disown %2

这使得该过程中没有什么不同,一个的状态nohup过程控制终端已被关闭之后。 例外是,如果控制终端未被重定向到文件,则任何输出都将丢失。

通常,如果不立即关闭终端窗口,则不希望完全从作业控制中删除该进程。 您可以通过-h标志的disown过程中,而不是为了纪念过程中忽略SIGHUP的信号,但否则,继续作为一个经常性的工作:

disown -h %1

在此状态下,可以使用正常的作业控制机制继续控制进程,直到关闭终端。 关闭终端后,如果您在启动时没有重定向到文件,则会再次遇到无法输出的进程。

要解决这个问题,您可以尝试在流程已经运行后重定向流程的输出。 这是本指南的范围,但你可以看看这个帖子让你将如何做到这一点的想法。

使用huponexit Shell选项

Bash还有另一种避免子进程的SIGHUP问题的方法。 huponexit外壳选项控制庆典是否会派其子处理SIGHUP信号,它退出时。

注意

huponexit选项只有当一个shell会话终止从外壳本身内开始影响SIGHUP行为。 当该应用的一些例子是,当exit命令或CTRL-D在会话中击中。

当一个壳会话通过终端程序本身结束(通过关闭窗口等),该命令huponexit没有影响。 而不是bash决定是否发送SIGHUP信号,终端本身将发送SIGHUP信号bash ,这将随后(正确地)信号传播到其子进程。

尽管有上述警告,该huponexit选项也许是一个最简单的。 您可以通过键入以下内容来查看此功能是开启还是关闭:

shopt huponexit

要打开它,请键入:

shopt -s huponexit

现在,如果你键入退出会话exit ,你的流程都将继续运行:

exit

这和最后一个选项有相同的程序输出注意事项,所以如果在关闭终端前很重要,请确保重定向了进程的输出。

结论

学习作业控制以及如何管理前台和后台进程将在命令行上运行程序时给您更大的灵活性。 而不是必须打开许多终端窗口或SSH会话,你经常可以得到通过几个停止和后台命令。