Python脚本在Linux服务器后台怎么保持运行?nohup与screen用法
详细讲解在Linux服务器断开SSH连接后如何让Python脚本保持后台运行,重点剖析nohup与screen两种常用工具的原理、完整操作步骤、输出重定向与进程管理技巧,并提供场景选型建议。
nohup 命令或终端复用工具 screen。本文将从终端退出的底层原因讲起,具体演示这两种工具的标准用法、日志处理与进程管理,并提供清晰的场景选型建议。
一、为什么终端断开会导致Python脚本停止运行?
初学者在Linux服务器上通过SSH连接运行Python脚本时,最常遇到的问题就是:只要本地电脑断网、合上笔记本屏幕或关闭SSH客户端终端,正在执行的数据抓取、模型训练或长轮询脚本就会立刻终止。
这是因为在Linux的会话管理机制中,每一个SSH登录都会创建一个伪终端会话(Session)。你在终端中直接输入的 python3 main.py 是当前登录Shell(通常是Bash)所衍生的子进程。当SSH连接断开或终端窗口关闭时,系统会向该会话名下的所有前台子进程广播发送挂起信号 SIGHUP (Signal Hangup, 信号值为1)。Python进程在接收到默认的SIGHUP信号后,操作系统会强制将其销毁,从而导致脚本中断。
因此,要让脚本在后台保持常驻,核心思路有两个:
- 阻断或忽略信号:使用
nohup包装命令,通知操作系统忽略一切SIGHUP挂起信号,让脚本脱离终端的连带退出。 - 托管会话环境:使用
screen创建一个独立的后台虚拟终端,将脚本放入该虚拟会话中运行,即便物理SSH断开,该虚拟会话依然由Linux系统常驻维持。
二、使用 nohup 运行 Python 脚本
nohup 是 "no hang up" 的缩写,属于 Linux 基础工具包中的内置命令。它的优势是开箱即用,无需额外安装软件,特别适合那些不需要人工键盘交互、只需要把标准输出记录在日志文件中的批处理脚本。
1. 完整的推荐运行命令
在实际生产环境中,请不要只执行简单的 nohup python app.py &,推荐使用以下标准语法:
nohup python3 -u task.py > task.log 2>&1 &
这条命令由几个不可或缺的关键部分组成:
nohup:告知操作系统忽略对随后命令的 SIGHUP 信号。python3 -u:重要参数。由于 Python 默认会对标准输出进行缓存(Block Buffering),如果不加-u(unbuffered),print()的输出可能长时间滞留在内存缓冲区中,导致查看日志文件时看不到最新内容。-u强制实时刷新输出流。> task.log:将脚本的标准输出(stdout)重定向写入到task.log文件中。若省略重定向目标,系统会默认在当前目录生成一个名为nohup.out的日志文件。2>&1:将标准错误(stderr,文件描述符2)重定向合并到标准输出(stdout,文件描述符1)中,确保报错回溯(Traceback)也能完整记录到同一份日志。&:将整个命令放入后台执行,立即释放当前终端提示符,允许继续输入其他命令。
2. 执行后你会看到什么?
在终端按下回车后,系统通常会输出一行提示,显示后台作业号与进程ID(PID),例如:
[1] 28941
[root@server ~]#
此时按一次回车,Shell 提示符恢复可用。进程 28941 已经在后台独立执行,你可以随时安全地输入 exit 关闭 SSH 窗口。
3. 实时跟踪输出与日志排查
当你想查看 Python 脚本是否有新的日志打印时,使用 tail 命令动态追踪日志文件末尾:
tail -f task.log
按 Ctrl + C 即可退出日志追踪视图,这不会影响后台运行的 Python 脚本本身。
4. 查找进程与优雅停止
如果需要停止后台运行的脚本,可以通过 ps 命令按脚本名检索对应的 PID:
ps -ef | grep task.py
终端会输出包含该脚本名称的进程列表,找到对应的第二列数字(PID),然后使用 kill 终止:
# 发送标准的终止信号(SIGTERM,允许脚本执行善后清理逻辑)
kill 28941
# 若脚本无响应,方可使用强制终止信号
kill -9 28941
三、使用 screen 管理交互式与长周期任务
nohup 虽然轻量,但有一个不可避免的限制:一旦送入后台,你就无法再次回到脚本的原始终端屏幕中。如果你的 Python 脚本包含键盘交互输入(例如 input() 询问确认)、带有 tqdm 动态进度条,或者你需要实时查看多项调试打印,screen 是更好的选择。
screen 是一个全屏终端多路复用器。它在系统底层维护着一个长久驻留的独立虚拟控制台。你可以在这个虚拟控制台里像操作普通电脑一样启动 Python,随时“脱离”(Detach)会话;下次登录服务器时,再“恢复”(Resume)连接进会话,屏幕上的进度条和光标位置依然保持原样。
1. 安装 screen
许多精简版 Linux 镜像可能未预装 screen,可通过系统包管理器快速安装:
# Ubuntu / Debian
sudo apt update && sudo apt install -y screen
# CentOS / RHEL / AlmaLinux
sudo yum install -y screen
# 或新版本系统:sudo dnf install -y screen
2. screen 的四步核心工作流
-
创建并进入命名会话:
screen -S spider_job执行后终端会清屏并进入一个新的虚拟终端界面。
-S spider_job给会话指定了一个易记的名字,便于后续识别。 -
正常启动 Python 脚本:
python3 run_spider.py在此界面下无需加
nohup或&,就像在日常电脑上直接前台运行一样。你能实时看到屏幕输出、按键提示和进度条。 -
脱离会话(Detach):
这是
screen最核心的操作。在会话内键盘依次按下:Ctrl + A,松开两个按键,然后按下字母D(代表 Detach)。终端会立即跳回你最初的外部登录控制台,并提示类似
[detached from 31024.spider_job]。此时,内部的 Python 脚本仍在完全独立地运行,你可以放心地关闭终端或关机。 -
重新连接会话(Resume):
当下一次通过 SSH 登录服务器时,输入以下命令查看已有的后台会话列表:
screen -ls终端会列出会话名及其状态:
There is a screen on: 31024.spider_job (Detached) 1 Socket in /run/screen/S-root.使用
-r参数重新恢复接入该会话:screen -r spider_job你将立刻重回之前正在运行的 Python 界面,无缝接续查看状态。
3. 任务结束与会话销毁
当 Python 脚本执行完毕,如果你不再需要该 screen 会话,直接在恢复连接的会话窗口内输入 exit 并回车,终端将提示 [screen is terminating],会话即被彻底销毁,不占用系统残留资源。
四、nohup 与 screen 深度对比与选型指南
两者并非替代关系,而是针对不同操作场景各有侧重。下表详细罗列了两者的核心特性差异:
| 比较维度 | nohup 方案 | screen 方案 |
|---|---|---|
| 环境要求 | Linux原生内置,无需安装 | 通常需通过 apt / yum 额外安装 |
| 终端交互性 | 无法交互(不能输入参数或按键确认) | 完整交互(支持任何终端交互与动态UI渲染) |
| 输出查看方式 | 必须重定向到日志文件(使用 tail -f 查看) |
直接重连进入虚拟屏幕,像本地控制台一样查看 |
| 多窗口管理 | 无,每一个任务都是单独的后台进程 | 支持在单个会话内切分多个窗口与标签页 |
| 适合的场景 | 定时数据处理、免交互批处理、简单Web后台脚本 | 爬虫实时监控、大模型长时间训练与微调、带进度条的任务 |
| 学习与操作成本 | 极低(单行命令组合即可生效) | 较低(需记住几个基础命令与快捷键) |
五、实战中的关键避坑事项
1. 日志文件迟迟不刷新(必须警惕缓冲区)
初次使用 nohup python app.py > app.log & 时,很多开发者会发现 tail -f app.log 没有任何输出,怀疑脚本卡死。这其实是 Python 的标准输出缓冲区在作怪。Python 在非 TTY(终端)环境下,会将标准输出缓存至数 KB 大小后才一次性写入磁盘。
-u 命令行标志:
nohup python3 -u app.py > app.log 2>&1 &
或者在环境变量中设置 export PYTHONUNBUFFERED=1。
2. 避免使用相对解释器路径(虚拟环境坑)
如果你的项目运行在 Poetry、Conda 或 venv 虚拟环境中,不要简单地写 python,否则一旦退出当前 Shell 会话,默认的环境变量可能导致脚本回退到系统的全局 Python,进而抛出 ModuleNotFoundError。
nohup /data/my_project/venv/bin/python -u app.py > app.log 2>&1 &
3. screen 恢复时提示 "There is no screen to be resumed matching..."
有时使用 screen -r my_spider 会提示无法连入,而使用 screen -ls 发现会话状态显示为 (Attached)。这通常发生在你的网络意外掉线时,系统仍然认为上一个连接还挂在上面。
-d -r 参数强制让远端先脱离,再重新连入本地:
screen -d -r my_spider
4. nohup 日志单文件体积过大问题
长期运行的 Python 后台任务如果直接 > app.log,几个月后该文件可能膨胀至数十 GB,导致服务器磁盘耗尽。在实际生产场景中,建议在 Python 脚本内部使用内置的 logging.handlers.RotatingFileHandler 模块按天或按大小(例如100MB)自动归档切割日志,保持系统磁盘的健康状态。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













