第 6 章 · 05 后台作业:`jobs`、`bg`、`fg`、`nohup`


文档摘要

第 6 章 · 05 后台作业: 、 、 、 本节摘要:有时候你要跑一个耗时任务(大文件下载、长时间训练),又不想让终端一直被占着。本节讲怎么把任务放后台、怎么管理后台作业。核心工具是 (放后台)、 (暂停到后台)、 (列后台作业)、 / (切回前台/后台继续)。但本节真正的重点是 ——它解决的不是一个简单问题,而是「为什么我关掉终端,后台进程就死了」的根因(SIGHUP 信号)。理解了 SIGHUP 与 nohup,你才懂得为什么生产环境应该用 而非 来管理长期服务。 内容来源:原项目「Linux 命令大全」 、 等,精选并套用体系化模板。 学习目标 阅读完本节,你应当能够: 用 把命令放后台执行,用 查看后台作业。 用 暂停前台进程,用 / 在后台继续或切回前台。

第 6 章 · 05 后台作业:jobsbgfgnohup

本节摘要:有时候你要跑一个耗时任务(大文件下载、长时间训练),又不想让终端一直被占着。本节讲怎么把任务放后台、怎么管理后台作业。核心工具是 &(放后台)、Ctrl+Z(暂停到后台)、jobs(列后台作业)、fg/bg(切回前台/后台继续)。但本节真正的重点是 nohup——它解决的不是一个简单问题,而是「为什么我关掉终端,后台进程就死了」的根因(SIGHUP 信号)。理解了 SIGHUP 与 nohup,你才懂得为什么生产环境应该用 systemd 而非 nohup 来管理长期服务。

内容来源:原项目「Linux 命令大全」command/nohup.mdcommand/jobs.md 等,精选并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. & 把命令放后台执行,用 jobs 查看后台作业。
  2. Ctrl+Z 暂停前台进程,用 bg/fg 在后台继续或切回前台。
  3. 说清「作业(job,Shell 概念)」与「进程(process,系统概念)」的差别。
  4. 解释「关终端导致后台进程死亡」的根因:Shell 退出时给所有子进程发 SIGHUP。
  5. nohup 让进程忽略 SIGHUP,从而在终端关闭后存活。
  6. 说清为什么生产环境该用 systemd 而非 nohup 管理长期服务。

一、设计动机:前台、后台与「被终端绑死」的问题

默认情况下,你在终端敲一个命令,它在前台跑,占着终端,你敲不了别的。有两种情况你想让它「不占终端」:

  1. 短任务后台化:敲 gimp &,图形程序启动了,终端还能继续用。
  2. 长任务挂后台:跑一个几小时的下载,你想关掉终端回家,明天回来看结果。

第一种用 & 就够。但第二种会撞上一个隐蔽的坑:你关掉终端,后台进程跟着死了。要理解为什么,得先理解 Shell 与子进程、以及 SIGHUP 信号。

作业 vs 进程

  • 进程(process):操作系统的概念,一个运行中的程序实例,有 PID。
  • 作业(job):Shell 的概念,一个作业可以包含一个或多个进程(比如管道 ls | grep 是一个作业,含两个进程)。jobs 命令看到的是作业,ps 看到的是进程。

Shell 给每个作业编号([1][2]),这个编号是 fg/bg 用的;而 PID 是 kill 用的。两者不同。

二、高频组合与实战

后台执行:&

long_task & # 放后台, 立刻回到提示符 [1] 12345 # [1] 是作业号, 12345 是 PID

暂停与切换:Ctrl+Zbgfgjobs

vim file.txt # 前台跑 vim # 按 Ctrl+Z # 暂停 vim, 回到 Shell [1]+ Stopped vim file.txt jobs # 列出后台作业 [1]+ Stopped vim file.txt fg %1 # 把作业 1 切回前台(继续 vim) bg %1 # 让作业 1 在后台继续(从 Stopped 变 Running)

💡 技巧:Ctrl+Z 暂停的进程状态是 T(停止,见第 03 节)。忘了它而退出 Shell,这个暂停的进程也会被清理。用 jobs 定期检查有没有被你遗忘的暂停作业。

nohup:让进程在终端关闭后存活

现在讲本节的核心问题:为什么关终端后台进程会死,以及 nohup 怎么解决。

根因:当你关闭终端窗口或断开 SSH,Shell 进程要退出。退出前,它给它的每个子进程/作业发 SIGHUP 信号(SIGHUP = "signal hangup",挂断)。大多数进程收到 SIGHUP 的默认行为是「退出」——所以你的后台任务跟着终端一起死了。

nohup 的解法:它启动进程时让进程忽略 SIGHUP,这样终端关闭、Shell 发 SIGHUP 时,进程不受影响。

nohup long_task & # 后台跑, 且忽略 SIGHUP, 关终端也不会死 # nohup 会把输出重定向到 nohup.out(因为终端没了, stdout 无处可去)
nohup ./train.py > train.log 2>&1 & # 更好的写法: 自己指定日志, 不用默认的 nohup.out

⚠️ 注意:nohup 只解决 SIGHUP 一个问题。它不保证「进程永远不死」——如果系统重启,进程还是会消失。真正可靠的长期服务管理用 systemd(第 8 章),它提供开机自启、崩溃重启、统一日志,这些 nohup 都没有。

三、踩坑与排错

坑 1:忘了重定向输出,nohup.out 满天飞

nohup ./script.sh & # 没指定输出, 默认写 nohup.out

多次跑会不断追加 nohup.out,且与脚本目录混在一起。始终显式重定向:nohup ... > app.log 2>&1 &

坑 2:Ctrl+Z 暂停的进程忘了恢复

vim big.txt # Ctrl+Z 暂停 # ... 干别的事, 忘了 vim 还暂停着 exit # 退出 Shell, 暂停的 vim 被清理, 没保存的内容丢了!

退出 Shell 前先 jobs 检查,把重要作业 fg 回来处理完。

坑 3:nohup 进程的 PID 没记

nohup ./job.sh > job.log 2>&1 & echo $! # $! 是上一个后台进程的 PID, 务必记下来 # 后续: kill <那个PID> 才能停掉它

不记 PID,以后想停就只能 ps aux | grep job.sh 慢慢找。

坑 4:以为 nohup 等于「守护进程」

nohup 让进程忽略 SIGHUP,但它仍是 Shell 的子进程,没有 setsid(脱离会话)、没有崩溃重启。要「真正的守护进程」,用 systemd 写个 service 单元(第 8 章)。

本节要点回顾

  1. & 放后台、Ctrl+Z 暂停、jobs 列作业、fg/bg 切换——这是 Shell 的作业管理。
  2. 作业(job,Shell 概念,[1]/[2] 编号)与进程(process,系统概念,PID)不同;fg 用作业号,kill 用 PID。
  3. 关终端导致后台进程死亡的根因:Shell 退出时给所有子进程发 SIGHUP。
  4. nohup 让进程忽略 SIGHUP,从而在终端关闭后存活;但务必重定向输出(> log 2>&1)、记下 PID($!)。
  5. nohup ≠ 守护进程:它不提供开机自启、崩溃重启;生产长期服务用 systemd(第 8 章)。

下一节抬到系统级资源观测——free(内存)、uptime(负载)、vmstat(虚拟内存与上下文切换)。


发布者: 作者: 灏天文库 转发
评论区 (0)
U