作业控制(JOB CONTROL)

Job control (作业控制) 指的是可以选择停止 (suspend,挂起) 进程执行,并且 可以在之后继续 (resume,恢复) 执行的能力。用户一般在交互的人机界面 中使用这种功能。界面是由系统的终端驱动和 bash 共同提供的。

shell 将每个管道分配给一个 作业(job)。 它保存一个当前运行的作业表,可以用 jobs 命令来列出。当 bash 启动一个异步的作业时 (background,后台执行), 它输出这样的一行:

[1] 25647

表明这个作业的作业号是 1,与作业相关连的管道中最后一个进程的 进程ID是 15647。管道中所有进程都是同一个作业的成员。 Bash 使用 作业(job) 概念作为作业控制的基础。

为简化作业控制的用户界面的实现,操作系统负责管理“当前终端的进程组” (current terminal process group ID) 的概念。这个进程组的成员 (进程组 ID 是当前终端进程组 ID 的进程) 可以收到键盘产生的信号,例如 SIGINT. 这些进程被称为 foreground(前台的)。 Background (后台的) 进程是那些进程组 ID 与终端不同的进程;这些进程不会收到键盘产生的信号。 只有前台进程可以从终端读或向终端写。后台进程试图读/写终端时,将收到终端驱动程序发送的 SIGTTIN (SIGTTOU) 信号。这个信号如果没有加以捕捉,将挂起这个进程。

如果 bash 运行其上的操作系统支持作业控制, bash 会包含使用它的设施。在一个进程正在运行的时候键入 suspend 挂起 字符 (通常是 ^Z, Control-Z) 将使这个进程暂停,将控制权还给 bash. 输入 delayed suspend, 延时挂起 字符 (通常是 ^Y, Control-Y) 将使这个进程在试图从终端读取输入时暂停,将控制权还给 bash. 用户接下来可以控制此作业的状态,使用 bg 命令使它在后台继续运行, fg 命令使它在前台继续运行,或 kill 命令将它杀死。^Z 会立即起作用,并且还有使等待中的 (pending) 输出和输入被忽略的附加副作用。

有很多方法来指代 shell 中的作业。字符 % 可以引入作业名。编号为 n 的作业可以用 %n 的形式来指代。作业也可以用启动它的名称的前缀,或者命令行中的子字符串来指代。例如, %ce 指代一个暂停的 ce 作业。如果前缀匹配多于一个作业, bash 报错。另一方面,使用 %?ce, 可以指代任何命令行中包含字符串 ce 的作业。如果子字符串匹配多于一个作业, bash 报错。符号 %%%+ 指代 shell 意义上的 current job,当前作业, 也就是前台被暂停的最后一个作业,或者是在后台启动的作业。 previous job,前一作业 可以使用 %- 来指代。在有关作业的输出信息中 (例如,命令 jobs 的输出),当前作业总是被标记为 +, 前一作业标记为 -.

简单地给出作业名,可以用来把它放到前台: %1``fg %1'' 的同义词,将作业 1 从后台放到前台。类似的, ``%1 &'' 在后台恢复作业 1,与 ``bg %1'' 等价。

当某个作业改变状态时,shell 立即可以得知。通常, bash 等待直到要输出一个提示符时,才会报告作业的状态变化,从而不会打断其他输出。 如果启用了内建命令 set-b 选项, bash 将立即报告这些变化。对 SIGCHLD 信号的陷阱将在每个子进程退出时执行。

如果在作业暂停时试图退出 bash, shell 打印一条警告消息。命令 jobs 可能被用来检查作业的状态。如果再次试图退出,中间没有其他命令,shell 不会打印 其他警告,暂停的作业将终止。