在 Linux 终端中,我们常常需要同时处理多个任务。比如,一边编辑代码,一边运行一个长时间的数据处理程序。Linux 的作业控制功能允许你在一个终端会话中管理多个进程,将它们切换到前台(foreground)或后台(background),甚至暂停或终止它们。

本教程将深入浅出地介绍 fgbgjobs 这三个核心命令,并重点讲解如何正确地关闭不再需要的后台作业。

博主博客

1. 核心概念:前台、后台与作业

在深入命令之前,我们需要理解几个关键概念:

  • 前台进程: 它占据你的终端,你可以直接与之交互(输入命令,查看输出)。一个终端同时只能有一个前台进程。
  • 后台进程: 它在后台运行,不占用终端。你可以在同一个终端里继续执行其他命令。后台进程的输出仍然会打印到终端,可能会干扰你的工作。
  • 作业 (Job): 由 Shell 管理的一个或多个进程组成的管道。当你运行一个命令时,就创建了一个作业。Shell 为每个作业分配一个唯一的作业号(例如 1, 2),用 % 号标识(如 %1)。
  • 进程状态
    • 运行中: 正在执行。
    • 已停止: 被挂起(通常由 Ctrl+Z 触发),暂停执行,等待恢复。

2. 核心命令详解

2.1 jobs —— 查看作业列表

jobs 命令是管理作业的起点,它显示当前 Shell 中所有作业的状态。

基本用法:

jobs

输出示例:

[1]-  运行中               sleep 1000 &
[2]+  已停止               vim myfile.txt
  • [1][2]:作业号。
  • +:表示这是当前作业,即最近被放入后台或暂停的作业。在默认情况下,不带参数的 fgbg 会作用于它。
  • -:表示上一个作业,即当前作业之前的那个作业。
  • 运行中已停止:作业的状态。
  • sleep 1000 &:执行的命令,末尾的 & 表示它是在后台启动的。

常用选项:

  • jobs -l:显示作业号、状态、进程ID(PID) 和命令。PID 在后续强制终止进程时非常有用。
  • jobs -p:只显示作业的进程组ID。

2.2 fg —— 将作业带到前台

fg (foreground) 命令将后台或暂停的作业切换到前台,使其占用终端并恢复执行。

基本语法:

fg [作业标识]
  • 不带参数: 将当前作业(带 + 号的作业)带到前台。
  • fg %n: 将作业号为 n 的作业带到前台。
  • fg %str: 将命令以 str 开头的作业带到前台。
  • fg %?str: 将命令包含 str 的作业带到前台。
  • fg %-: 将上一个作业(带 - 号的作业)带到前台。

示例:

# 启动一个后台任务
sleep 300 &
[1] 12345

# 将任务带回前台
fg
# 或
fg %1

现在,sleep 命令占据了终端。你可以按 Ctrl+C 来终止它,或按 Ctrl+Z 再次暂停它。

2.3 bg —— 将作业在后台恢复运行

bg (background) 命令将一个已停止(暂停)的作业放到后台继续执行。它非常适合用于让被 Ctrl+Z 暂停的任务在后台默默运行。

基本语法:

bg [作业标识]
  • 不带参数: 将当前作业(带 + 号)放到后台继续运行。
  • bg %n: 将作业号为 n 的作业放到后台继续运行。

示例:

  1. 启动一个消耗 CPU 的任务,并立即用 Ctrl+Z 暂停它:

    $ grep -r "error" /var/log/
    ^Z
    [1]+  已停止               grep -r "error" /var/log/
    
  2. 查看作业状态,确认它已停止:

    $ jobs
    [1]+  已停止               grep -r "error" /var/log/
    
  3. bg 命令让它在后台继续执行:

    $ bg
    [1]+ grep -r "error" /var/log/ &
    
  4. 现在,任务在后台运行,你可以继续输入其他命令了。再次查看作业状态:

    $ jobs
    [1]+  运行中               grep -r "error" /var/log/ &
    

3. 如何关闭后台作业

这是日常操作中非常常见的需求。关闭一个后台作业主要有两种方法:优雅地将其调到前台再关闭,或者直接通过 PID 强制终止

方法一:通过 fg + Ctrl+C (推荐,更友好)

这是最安全、最符合直觉的方法,尤其适用于那些需要优雅退出的程序(如文本编辑器、开发服务器等)。

步骤:

  1. 使用 jobs 查看所有后台作业,找到你想要关闭的作业号。
  2. 使用 fg %作业号 将该作业调到前台。
  3. Ctrl+C 发送中断信号 (SIGINT),程序通常会执行清理工作后退出。

示例:

$ jobs
[1]-  运行中               python3 long_running_script.py &
[2]+  已停止               vim important_file.txt

# 关闭 vim 编辑器 (作业号 2)
$ fg %2
# 终端显示 vim 界面,按 Ctrl+C 无效 (vim 不响应此信号)
# 在 vim 中,应该输入 :q 退出。这里假设程序是支持 Ctrl+C 的

# 关闭 Python 脚本 (作业号 1)
$ fg %1
^C
# 回到终端提示符,作业已终止
$ jobs
[2]+  已停止               vim important_file.txt

方法二:使用 kill 命令 (更强大,用于强制终止)

如果一个程序无法通过 Ctrl+C 终止,或者你想在不切换到前台的情况下直接关闭它,可以使用 kill 命令。kill 通过进程ID (PID) 或作业号发送信号。

2.1 通过作业号关闭

kill 命令也可以直接接受作业号,语法是 kill %作业号

$ jobs
[1]-  运行中               sleep 1000 &
[2]+  运行中               tail -f /var/log/syslog &

# 终止作业 1 (sleep)
$ kill %1
$ jobs
[1]-  已终止               sleep 1000
[2]+  运行中               tail -f /var/log/syslog &

kill 默认发送的是 SIGTERM (15) 信号,这是一个友好的终止信号,允许程序进行清理。如果程序没有响应,可以使用 -9 (SIGKILL) 强制终止:

$ kill -9 %2
$ jobs
[2]+  已杀死               tail -f /var/log/syslog

2.2 通过 PID 关闭 (最直接)
当作业号丢失或需要从另一个终端进行操作时,直接使用PID是最可靠的。

  1. 使用 jobs -l 查看作业对应的PID。
  2. 使用 kill PID 终止进程。
$ jobs -l
[1]-  12345 运行中               sleep 1000 &
[2]+  12346 运行中               tail -f /var/log/syslog &

$ kill 12345
$ kill 12346
$ jobs
[1]-  已终止               sleep 1000
[2]+  已终止               tail -f /var/log/syslog

方法三:清理所有后台作业

如果你想终止当前 Shell 下的所有后台作业,可以使用以下命令组合:

# 终止所有后台作业 (发送 SIGTERM)
kill $(jobs -p)

# 或者,如果作业不响应,强制终止 (发送 SIGKILL)
kill -9 $(jobs -p)

jobs -p 会输出所有作业的进程组ID,然后 kill 命令会依次终止它们。

4. 完整操作流程示例

假设你正在开发一个 Web 应用:

  1. 启动开发服务器(前台运行)

    npm start
    

    服务器启动,终端被占用。

  2. 临时暂停服务器,处理其他事务
    按下 Ctrl+Z

    [1]+  已停止               npm start
    
  3. 查看作业状态

    jobs
    
    [1]+  已停止               npm start
    
  4. 在后台继续运行服务器

    bg
    
    [1]+ npm start &
    
  5. 现在,你可以自由地执行其他命令

    ls -la
    git status
    
  6. 完成工作,想关闭服务器
    查看作业并终止它。

    $ jobs
    [1]+  运行中               npm start &
    
    # 方法一:优雅终止
    $ fg %1
    ^C
    # 服务器进程关闭
    
    # 或者,如果它不响应,直接 kill
    # $ kill %1
    
  7. 再次查看,确认作业已清理

    jobs
    
    (无输出)
    

5. 进阶技巧与注意事项

5.1 结合 nohupdisown

  • nohup: 当你启动一个命令并希望它在你退出终端后继续运行时,使用 nohup command &。它会忽略挂断信号 (SIGHUP)。
  • disown: 如果你已经在后台运行了一个作业,并希望将其从当前 Shell 的作业表中移除,使其不受终端关闭的影响,可以使用 disown %作业号。之后,jobs 将不再显示它,但进程仍在运行。

5.2 注意事项

  • 终端关联性: 大多数作业与启动它的终端会话关联。如果关闭终端窗口,默认情况下,该终端下的所有后台作业也会收到挂断信号 (SIGHUP) 并被终止。nohupdisown 是避免这种情况的关键。
  • 输出干扰: 后台作业的输出(如 stdoutstderr)仍然会打印到终端。如果不想被干扰,可以在启动命令时重定向输出,例如 command > /dev/null 2>&1 &
  • 交互式程序: 像 vimsshtop 这类需要终端交互的程序,无法直接在后台运行。如果你用 & 启动它们,它们通常会立即被暂停。正确的做法是先在前台启动,然后按 Ctrl+Z 暂停,再用 bg 放到后台。但此时它们仍会因无法接收输入而处于停止状态,无法正常工作。对于此类程序,最佳实践是使用 screentmux 等终端复用器。

总结

命令 作用 常用示例
jobs 查看当前 Shell 的所有后台/暂停作业 jobs -l
fg 将作业调到前台 fg %1fg
bg 将暂停的作业在后台恢复运行 bg %1bg
kill 终止一个作业或进程 kill %1kill 12345
Ctrl+Z 暂停当前前台作业
Ctrl+C 终止当前前台作业

掌握 fgbgjobskill 的组合使用,能让你在 Linux 命令行下更加高效、灵活地管理多任务,从一个被动的命令执行者,变成一个主动的作业调度者。