Linux 后台进程管理方法
目录
问题
用 telnet/ssh 登录远程 Linux 服务器运行耗时任务时,网络断开或关闭终端会导致进程中断。需要使进程在后台稳定运行。
HUP 信号与 hangup
Unix 早期,每个终端通过 modem 与系统通信。用户 logout 时 modem 挂断(hang up),给终端发送 HUP(hangup)信号关闭所有子进程。现代系统中网络断开时也会触发 HUP 信号。
解决方案:要么让进程忽略 HUP 信号,要么让进程运行在新的会话里成为不属于该终端的子进程。
nohup
命令前加 nohup,让命令忽略 hangup 信号。标准输出和错误默认重定向到 nohup.out,可用 > filename 2>&1 指定输出文件。
nohup ping www.ibm.com &
ps -ef | grep ping
setsid
运行程序在新会话中,使其不属于当前终端的子进程。
setsid ping www.ibm.com
ps -ef | grep ping
# 进程父进程 ID(PPID)为 1(init 进程)
subshell(& 和 ())
将命令放在 () 中并加 & 后台运行:
(ping www.ibm.com &)
ps -ef | grep ping
# 进程 PPID 也为 1
# 无法通过 jobs 查看,但可用 ps -ef 看到
disown(事后补救)
若命令已提交但未加保护,可用 disown 补救。前提是已用 & 放入后台或用 Ctrl-z 暂停后用 bg 恢复。
用法:
disown -h %jobspec # 使指定作业忽略 HUP
disown -ah # 所有作业忽略 HUP
disown -rh # 正在运行的作业忽略 HUP
disown 示例 1(命令已后台运行)
cp -r testLargeFile largeFile &
jobs
disown -h %1
ps -ef | grep largeFile
logout
disown 示例 2(命令未后台运行)
先用 Ctrl-z 暂停,再用 bg 恢复,最后 disown:
cp -r testLargeFile largeFile2
# 按 Ctrl-z
bg %1
jobs
disown -h %1
ps -ef | grep largeFile2
Ctrl-z 与 jobs 配合
Ctrl-z:暂停当前进程jobs:查看所有作业及作业号bg %jobspec:在后台继续运行fg %jobspec:恢复到前台
disown 后,作业将从作业列表中移除,无法用 jobs 查看,但仍可用 ps -ef 找到。
screen(大批量场景最佳选择)
screen 是虚拟终端管理器,在一个真实终端下运行多个伪终端。在 screen 会话中启动的进程的父进程是 screen(PID 为 1 的 init),不再属于 ssh 终端的子进程,从而避免 HUP 信号影响。
常用选项:
screen -dmS sessionname # 建立名为 sessionname 的断开模式会话
screen -list # 列出所有会话
screen -r sessionname # 重新连接会话
# 在 screen 中按 Ctrl-a d 暂时断开
示例:
screen -dmS Urumchi
screen -list
# 输出:12842.Urumchi (Detached)
screen -r Urumchi
# 连接后可运行任意命令,关闭 ssh 后进程继续运行
进程树对比(假设 ping 进程 ID 为 9488):
不使用 screen: 进程树为 init -> sshd -> bash -> ping,ssh 断开时 bash 收到 HUP 并传递给 ping。
使用 screen: 进程树为 init -> screen -> bash -> ping,ssh 断开时 screen 不会收到 HUP。
总结
选择方案根据场景:
- 临时一次性任务:nohup 或 setsid 最简便
- 任务已在运行、需补救:disown + Ctrl-z + bg
- 大量长期运行任务:screen 是最佳选择