Contents

bash中的工作和工作控制

1. 概述

每当我们在bash中运行命令时,它都会作为作业运行。了解如何管理作业意味着我们可以更好地控制我们的外壳。 在本教程中,我们将探讨bash中的作业,以及它们与进程的关系。我们将学习如何在后台启动、暂停、恢复和运行它们。

2. bash Shell中的进程和作业

Linux 中的进程是指任何正在运行的程序。例如,当我们运行*ls 时,它作为一个进程运行。如果我们搜索文件名,通过使用ls -l*并将结果传递给grep ,我们实际上正在运行两个进程:

$ ls -l | grep script
-rwxr-xr-x 1 ubuntu users 18 Aug  2 21:44 myscript.sh

由于一个命令可能会导致多个进程运行,因此它在bash shell 中表示为一个作业,并且是从单个命令或脚本运行的进程的逻辑分组

3. 暂停和恢复工作

在我们的ls示例中,我们通常希望执行立即完成并返回到 shell 提示符。但是如果一个命令需要一段时间,我们需要等待它终止。而且,如果我们想在等待时运行另一个命令,我们需要打开另一个 shell。

假设我们运行了一个find 命令,它已经显示了我们认为正在寻找的文件。我们可以按Ctrl+C来停止命令。但是,也许最好暂停find以便我们可以仔细检查,并在必要时恢复它。

我们可以使用Ctrl+Z暂停当前作业:

$ find . -name "*.java"
./code/com/my/package/Main.java
^Z
[1]+  Stopped                 find . -name "*.java"

在这里,我们运行find命令并在看到一些输出后按下Ctrl+Z ( ^Z )。暂停作业导致提示我们显示作业编号*[1]和一条消息,表明它已停止*。我们可以通过这个作业号来引用暂停的作业,稍后我们会看到。

我们应该注意,即使 shell 说作业已停止,但实际上它是暂停的——不是终止的——我们将能够恢复它。

当我们暂停find命令时,我们将返回 shell 提示符以运行更多命令。如果我们希望恢复查找操作,可以使用fg 命令:

$ fg
find . -name "*.java"
./code/com/my/package2/Util.java

在这里,最后一个暂停的作业被恢复并在前台运行,占用 shell 直到它完成,或者我们选择停止或再次暂停它。

4. 作业控制

要了解我们可以对作业做些什么,让我们启动两个长时间运行的作业,然后在每个作业之后按Ctrl+Z以暂停它们:

$ make -j4
^Z
[1]+  Stopped                 make -j4
$ find . -name "*.java"
^Z
[2]+  Stopped                 find . -name "*.java"

4.1. 列出工作

我们使用jobs 命令列出作业:

$ jobs
[1]-  Stopped                 make -j4
[2]+  Stopped                 find . -name "*.java"

jobs命令用*+号标记上一个暂停的作业,用-标记上一个停止的作业。如果我们使用fg*和其他没有作业编号的作业命令,则暗示最后一个暂停的作业。

4.2. 在前台恢复特定工作

fg命令允许我们通过作业编号恢复特定作业。作业开始时会输出作业名称:

$ fg %1
make -j4

4.3. 在后台运行作业

我们还可以在后台恢复工作。后台作业在不占用 shell 的情况下运行。它无法访问 shell 输入,但它仍然可以输出到 shell:

$ bg %1
[1]+ make -j4 &

fg一样,我们可以在**bg命令中省略作业号以在后台恢复上一个暂停的作业:

$ bg
[2]+ find . -name "*.java" &

4.4. 在后台开始工作

我们还可以通过在命令行末尾添加与号 (&) 字符来直接作为后台进程启动作业:

$ find . -name "*.java" &
[1] 1726

5. 消息:有已停止的作业

有时当我们尝试通过按Ctrl+D或使用*logout *退出 shell 时,我们可能会收到一条错误消息:

$ logout
There are stopped jobs.

bash显示此消息时,它还会阻止注销。

这是因为bash不允许我们在有暂停的作业时退出 shell。当前 shell 的进程管理它的工作。当我们暂停一项工作时,它会处于未完成的状态。如果我们在作业暂停的情况下退出 shell,我们可能会丢失一些关键数据。

因此,我们需要在退出 shell 之前处理这些暂停的作业。

5.1. 列出要处理的作业

为了决定如何处理我们的工作,让我们列出它们:

$ jobs
[1]-  Stopped                 python
[2]+  Stopped                 find . -name "*.java" > javafiles.txt

根据这些工作,我们可能希望让它们继续运行或终止它们。

5.2. 保持工作运行

我们已经了解了如何让作业在后台运行:

$ bg %2
[2]+ find . -name "*.java" > javafiles.txt &

正如我们之前提到的后台作业,该作业在后台运行时仍然可以输出到 shell。如果我们现在退出 shell,如果它尝试输出到 shell,那么作业可能会终止,因为 shell 不再存在。当它接收到某些信号时,它也可能被杀死。

为避免这种情况,我们可以使用disown命令从当前 shell 中删除后台作业

$ disown %2
$ logout

这将确保后台作业即使在 shell 退出后也能继续在后台运行。

5.3. 杀死job

或者,我们可以使用kill 命令杀死不需要的作业:

$ kill %1
[1]+  Stopped                 python
$ logout

kill允许我们使用*%1*作为作业编号,尽管它也常用于通过进程 ID 终止进程。