Linux进程前后台管理:jobs、fg、bg、nohup、disown

Linux进程前后台管理:jobs、fg、bg、nohup、disown

你有没有过这种经历:在终端里跑一个耗时脚本,手一抖 Ctrl+C 把它掐了;或者 SSH 连上去启动服务,关掉窗口进程就没了。问题的根源在于------终端和进程之间有一条「会话」的脐带,一旦终端断开,内核会向它启动的进程发信号。这一篇把 &、Ctrl+Z、jobs、fg、bg、nohup、disown 讲清楚,掌握后就能自如地让进程在后台安稳运行。

一、前台与后台:终端只能伺候一个前台

Linux 里,一个终端(terminal)同一时刻只有一个前台进程组 ,键盘输入、Ctrl+C(SIGINT)、Ctrl+Z(SIGTSTP)都发给这个前台进程组。其他进程要么在后台跑,要么被暂停。

  • 前台 :占着终端,能接收键盘输入和 Ctrl+C
  • 后台:在跑,但不占终端,键盘信号发给不到它
  • 暂停 :被 SIGSTOP/SIGTSTP 冻结,不占 CPU,等 fg 或 bg 唤醒

理解这条主线,后面所有命令都顺了。

二、&:启动即入后台

语法格式

复制代码
命令 &

在整条命令末尾加一个 &,shell 会把它放进后台,立即把提示符还给你。

示例与预期输出

复制代码
sleep 300 &

预期输出:

复制代码
[1] 12345
  • [1] 是作业号(job number),是 shell 给这个任务编的号,只在当前 shell 有效
  • 12345 是进程号(PID),是内核编的,全局唯一

两者区别要记牢:作业号管前后台切换,PID 管杀进程。

注意:& 不等于「断开也不死」

command & 只是放后台,它仍然属于当前终端会话。关掉终端,它照样死 。想断开也不死,得配合 nohup 或 disown,见后文。

三、Ctrl+Z:把前台进程按暂停

正在跑的进程想临时腾出终端,按 Ctrl+Z,它会被 SIGTSTP 暂停并扔到后台(状态 T):

复制代码
$ vim bigfile.log
^Z
[1]+  Stopped                 vim bigfile.log

注意是停止 不是后台运行 ------它冻结了,不消耗 CPU。想让它继续跑,用 bg;想回到前台,用 fg。

四、jobs:查看当前 shell 的后台任务

语法格式

复制代码
jobs [选项]

常用参数

参数 说明
-l 同时显示 PID
-r 只显示运行中的任务
-s 只显示已停止的任务

示例与预期输出

复制代码
jobs -l

预期输出:

复制代码
[1]-  12345 Running                 sleep 300 &
[2]+  12346 Stopped                 vim bigfile.log

符号解释:

  • +:当前任务,fg 不带参数时默认操作它
  • -:前一个任务
  • Running / Stopped:运行中 / 已暂停

五、fg / bg:前后台切换

语法格式

复制代码
fg [%作业号]     # 把后台任务调回前台
bg [%作业号]     # 让暂停的任务在后台继续跑

作业号要带 %,如 %1;不带参数则操作当前(+)任务。

示例与预期输出

把 [2] 的 vim 唤回前台:

复制代码
fg %2

让刚才暂停的 vim 转到后台继续(这个例子意义不大,但换成 rsync 就很有用):

复制代码
bg %1

预期输出:

复制代码
[1]+ sleep 300 &

⚠️ 后台任务仍会往终端写输出

后台进程的 stdout/stderr 默认还是连到终端,它的输出会突然插进你正在敲的命令里,把屏幕弄乱。启动时就重定向掉:

复制代码
long_task.sh > run.log 2>&1 &

这也是写后台任务脚本的标配姿势。

六、nohup:挂断也不死

nohup = no hang up。它让命令忽略 SIGHUP 信号 ,并把输出默认重定向到 nohup.out。

语法格式

复制代码
nohup 命令 [参数] &

示例与预期输出

复制代码
nohup python3 train.py > train.log 2>&1 &

预期输出:

复制代码
[1] 12345
nohup: ignoring input and appending output to 'nohup.out'

(这里因为已经手动重定向到 train.log,所以不会再生成 nohup.out。)

关键点

  • nohup 只解决 SIGHUP,不解决 stdin。它在启动时会把 stdin 重定向到 /dev/null,所以别再指望进程能读键盘。
  • 通常写作 nohup cmd > out.log 2>&1 &:忽略挂断 + 标准输出 + 错误输出 + 后台,一步到位。
  • 想停止它,用 ps/pgrep 找到 PID 再 kill,因为作业号在关掉 shell 后就没了。

⚠️ nohup 不等于守护进程

nohup 进程仍然是普通进程,跟着系统走,但不会开机自启、不会自动重启、不受服务管理 。生产环境的长期服务应该交给 systemd(见第 35 篇),nohup 只适合临时跑个长任务。

七、disown:事后补救

有时进程已经在跑了(可能还带 &),你才想起来「糟了,关终端就没了」。这时不用重开,disown 可以把作业从 shell 的作业表里摘掉,让它不再收到 SIGHUP。

语法格式

复制代码
disown [选项] [%作业号]

常用参数

参数 说明
-h 只标记为「不接收 SIGHUP」,任务仍留在 jobs 列表
-a 移除所有作业
-r 只移除运行中的作业

示例与预期输出

复制代码
sleep 300 &
disown %1
jobs

jobs 会显示 [1] 已不在列表里,但 sleep 进程还在:

复制代码
pgrep -a sleep
12345 sleep 300

nohup vs disown 怎么选

维度 nohup disown
使用时机 启动时就加 跑起来后补
输出 默认写 nohup.out 不变,仍指向原位置
灵活性 低,写死在命令前 高,可对已有任务操作

八、⚠️ 常见错误

  1. 以为 & 就能防断开 。& 只是后台,SSH 一断照样收到 SIGHUP 退出。要断开也不死,必须 nohup 或 disown,或用 screen/tmux。
  2. 用 Ctrl+Z 后忘了恢复 。很多人 Ctrl+Z 停了 vim 又去干别的,回来发现 jobs 里堆了一串 Stopped,占用着资源。记得 fg 或 kill %n 清理。
  3. nohup 没重定向输出导致磁盘写满 。默认写 nohup.out 且不断追加,长时间跑的任务如果没重定向,某天会把 / 撑爆。永远显式 > xxx.log 2>&1。
  4. 作业号跨 shell 失效 。jobs 的作业号只在当前 shell 里认,新开一个终端 fg %1 会报 no such job。跨会话管理进程要靠 PID 或 tmux。
  5. kill %1 与 kill 1 搞混 。%1 是作业号,1 是 PID 1(init),kill 1 可能把系统搞挂(虽然一般会权限拒绝)。杀后台任务时写清 %。

九、原理探究:SIGHUP 到底是什么

SIGHUP 字面是「挂断」(Hang Up),起源于拨号上网时代------调制解调器掉线,内核就向该终端上的所有进程发 SIGHUP。如今终端虽不用电话线,但这个信号的语义保留了下来:

当控制终端(controlling terminal)关闭时,内核会向前台进程组和该会话的所有进程发送 SIGHUP。

一条 SSH 连接对应一个会话(session),会话里有一个控制终端。你关掉 SSH 窗口,控制终端消失,内核给会话里的进程发 SIGHUP,默认动作是终止进程。

这就解释了三件事:

  • nohup 为什么有效:它启动进程时就把 SIGHUP 忽略(signal(SIGHUP, SIG_IGN)),收到也不理。
  • disown 为什么有效:修订进程的作业表,让 shell 在退出时不向它转发 SIGHUP。
  • 为什么有的进程「关终端也没事」:它可能自己就忽略了 SIGHUP,或者已经脱离了这个会话(如 systemd 启动的服务)。

顺带理解「进程组 / 会话」:一个会话包含多个进程组,一个进程组包含多个进程。Ctrl+C 发给前台进程组 全体,所以 a | b | c 管道里三个进程会一起收到 SIGINT。想只杀管道里最后一个,得用 kill 精确到 PID。

十、更靠谱的方案:tmux 与 systemd

nohup/disown 是轻量解决方案,但有两个硬伤:进程输出只能靠日志捞、进程管理混乱(一多就靠 ps 找 PID)。

实际工作中更推荐:

复制代码
# 方案一:tmux,会话可随时 attach/detach
tmux new -s deploy
# 在里面跑任务,然后 Ctrl+B 再按 D 脱离;重连:
tmux attach -t deploy

# 方案二:写 systemd 服务,长期服务交给系统管
sudo systemctl start myapp
sudo systemctl enable myapp   # 开机自启
journalctl -u myapp -f        # 看日志
  • 临时长任务 (跑个数据、下个大文件):tmux 最优,随时回来接着看。
  • 长期服务 (web、mq、agent):写 systemd unit,开机自启、崩溃重启、日志集中,见第 35、36 篇。

nohup/disown 理解原理是必须的,但日常尽量用 tmux 和 systemd 替代。

相关推荐
JavaEdge.1 小时前
Docker Compose部署Dify
运维·docker·容器
企业解惑小助手1 小时前
大型企业终端如何统一管理排障实录:批量终端策略不生效问题排查
运维·服务器·网络·域智盾软件
luo_guibin1 小时前
almalinux9新系统常规命令操作
运维·服务器
进击的荆棘2 小时前
Linux系统——库的原理与制作之ELF文件的形成与加载的过程(下)
linux·动静态库
CrazyMo_2 小时前
鸿蒙高级——内存专用之linux-reserve-memory 方案简介
linux·运维·服务器
Sammyyyyy2 小时前
jev-ultrafast 实战:浏览器操作代理加本地 AI 网关,把云控制台配置做成自动化流水线
运维·人工智能·自动化·ai编程·servbay
灯澜忆梦2 小时前
【Linux】#5 | 文件与目录基础操作命令
java·linux·运维
逐梦之程2 小时前
EXCEL与DBC格式互转软件
运维·服务器·网络
yychen_java2 小时前
第十二篇:完整项目实战——构建可验证的能源智能运维 Agent 中枢
运维·人工智能·能源