Linux后台运行Python脚本并保存日志的方法

小林子
小林子
发布时间:2026-10-31 | 8人浏览过
原创

详细讲解在Linux系统中后台持久化运行Python脚本并完整保存标准输出与错误日志的常用方案,涵盖nohup重定向语法拆解、-u禁用输出缓冲、后台进程启停维护以及systemd生产级守护配置。

在 Linux 服务器上执行爬虫、长时间计算或服务监听类 Python 脚本时,如果直接在终端前台运行,一旦 SSH 连接意外中断或主动关闭窗口,进程就会随之终止。要让程序在退出终端后继续稳定运行,并将标准输出与错误信息完整保存到磁盘文件中,核心方法是解除终端挂起信号(SIGHUP)关联、转入系统后台执行,并通过 I/O 重定向将数据流实时写入日志文件。
Linux后台运行Python脚本并保存日志的方法
图 1:Linux 环境下终端会话脱离与后台进程持久化日志架构示意图

一、为什么直接后台运行还不够?核心问题与运行原理

很多初学者在执行脚本时习惯在末尾添加一个 & 符号(例如 python3 app.py &)。虽然 & 能够让命令立即让出终端提示符并在后台运行,但该进程依然挂载在当前控制终端(tty / pts)的会话组中。当 SSH 会话断开或终端窗口关闭时,系统会向该会话名下的所有子进程发送 SIGHUP(Hangup)挂起信号,导致后台脚本瞬间被强制终止。

此外,Linux 控制台默认将输出直接打印在屏幕伪终端设备上。一旦失去屏幕终端,未重定向的数据流将无处可去。因此,要实现真正的“免打扰后台运行并留痕”,必须同时满足三个技术条件:

  • 屏蔽终止信号:让进程忽略终端退出时发出的 SIGHUP 信号;
  • 解绑交互输入输出:将进程的标准输出(stdout)和标准错误(stderr)转接到磁盘文件;
  • 解决 I/O 缓冲延迟:防止 Python 默认的缓冲机制导致日志迟迟不写盘。

二、最通用的基础方案:nohup 结合 I/O 重定向

nohup(no hang up)是 Linux 系统原生自带的实用工具,用于运行不受挂起信号影响的命令。它是单机运行中小型脚本最便捷、最常用的方案。

1. 标准执行命令

# 标准单行启动模板(替换为您自己的脚本名和日志路径)
nohup python3 -u script.py > app.log 2>&1 &
Linux后台运行Python脚本并保存日志的方法
图 2:nohup 后台运行与输出流重定向各参数语法拆解

2. 各参数详细拆解

这条经典命令由五个核心部分组合而成,每一个选项都承担着明确的功能职责:

  • nohup:告知操作系统忽略所有 SIGHUP 信号。即便远程登录连接因网络波动断开或用户主动输入 exit 退出,该进程也不会受波及;
  • python3 -u:极其关键的参数。-u(unbuffered)强制 Python 对标准输出和标准错误采用无缓冲模式,每产生一行 print 就立即同步写到磁盘,解决日志文件长时间空白的顽疾;
  • > app.log:将文件描述符 1(标准输出 stdout)重定向到名为 app.log 的文件。单大于号 > 表示每次启动覆盖原文件;如果您希望保留历史日志并在末尾追加,请使用双大于号 >> app.log;
  • 2>&1:将文件描述符 2(标准错误 stderr)重定向到描述符 1 当前指向的位置。这样无论是程序中的正常 print 输出,还是未捕获的报错堆栈信息(Traceback),都会统一按时间顺序收拢到同一个日志文件中;
  • &:通知 Shell 将该命令作为后台作业执行,回车后 Shell 立即交还控制权,允许在当前终端继续操作。
标准输入防挂起建议:如果 Python 脚本中偶然存在 input() 调用,转入后台后可能因等待终端输入而被系统置于暂停挂起状态(T T 状态)。为彻底防范此问题,可以在命令中显式封闭输入流:nohup python3 -u script.py < /dev/null > app.log 2>&1 &。

三、后台任务的日常维护:查看、确认与停止

命令提交到后台后,并不意味着维护工作的结束。读者需要掌握如何确认脚本正在健康运行、如何动态观察输出,以及如何安全平稳地停止任务。

Linux后台运行Python脚本并保存日志的方法
图 3:Linux 后台任务全生命周期规范操作步骤流程

步骤 1:获取与记录进程 ID(PID)

在执行带 & 的命令后,终端第一行通常会返回两个数字,例如 [1] 28541。其中方括号内的 1 是作业编号(Job ID),后面的 28541 则是系统赋予的进程 ID(PID)。

在编写自动化脚本或部署流程时,推荐利用 Shell 内置变量 $!(代表最后一个置于后台的进程 PID)直接将进程号保存至文件中:

nohup python3 -u script.py > app.log 2>&1 & echo $! > app.pid

步骤 2:验证进程运行状态

脚本启动数秒后,应主动检查进程是否存活,排除因环境缺包或语法错误引发的“启动即闪退”:

# 方式 A:通过 ps 与 grep 查找
ps aux | grep script.py

# 方式 B:通过 pgrep 快速列出对应 PID
pgrep -fl script.py

输出示例(明确标示进程运行中):

user   28541  1.2  0.8 124356 32412 pts/1    S    10:15   0:02 python3 -u script.py

步骤 3:实时动态追踪日志

使用 tail -f 可以持续追踪日志增量,效果与直接在终端前台查看完全一致。按 Ctrl + C 仅退出 tail 监视界面,绝不会影响后台运行中的 Python 脚本。

# 查看末尾 50 行并开启动态滚动监听
tail -n 50 -f app.log

步骤 4:安全终止后台进程

停止正在后台运行的 Python 脚本时,务必优先采用 SIGTERM(信号 15)让程序优雅关闭。只有当程序无响应、处于僵死状态时,才考虑强制发送 SIGKILL(信号 9):

# 优雅终止(推荐:允许 Python 执行 try...finally、关闭数据库连接与保存文件)
kill -15 28541

# 若已记录 app.pid 文件,可直接调用:
kill -15 $(cat app.pid)

# 仅在无响应超时时使用强制终止:
kill -9 28541

四、为什么日志文件经常为空?深入解析 Python 输出缓冲

许多开发者在初次使用 nohup 时常遇到一个困惑:明明程序在后台运行且无报错,但通过 cat app.log 或 tail -f app.log 查看时,日志文件长时间显示为 0 字节,直到脚本全部执行完毕或者强制杀死时,日志才瞬间喷涌而出。如果程序在运行途中意外宕机,最后的崩溃信息将彻底丢失。

Linux后台运行Python脚本并保存日志的方法
图 4:Python 默认块缓冲机制与 -u 无缓冲模式写盘对比

背后的原因:TTY 与 Block Buffering

在 Linux 体系中,C 标准 I/O 库和 Python 会自动感知当前输出流的目标类型:

  • 行缓冲(Line Buffered):当输出目标是交互式终端(TTY / PTS)时,每次遇到换行符 就会自动刷新屏幕;
  • 全缓冲(Block Buffered):当输出被重定向到非终端设备(例如普通的磁盘文件 app.log)时,系统为了节省高频磁盘 I/O 开销,默认开启全缓冲模式。输出内容会被暂存在 4KB 或 8KB 大小的内存缓冲区中,只有当缓冲区被填满或程序正常退出时,才会执行实际的写盘操作。

三种针对性的解决办法

要让日志能够实时、逐行出现在文件中,可以根据部署环境选择以下任意一种手段:

  1. 命令行显式传参(最推荐):在执行解释器时加上 -u,即 python3 -u script.py > app.log 2>&1 &;
  2. 配置环境变量:在执行前设定 PYTHONUNBUFFERED=1,例如 export PYTHONUNBUFFERED=1 或 PYTHONUNBUFFERED=1 nohup python3 script.py ...;
  3. 在 Python 代码内主动刷新:修改关键代码中的 print 语句,加上刷新参数:print("处理进度", flush=True),或显式调用 import sys; sys.stdout.flush()。

五、生产环境高可用方案:使用 systemd 注册为系统守护服务

nohup 适合临时任务和开发测试,但若面对的是生产环境下的核心爬虫、消息监听服务或 Web API,它缺乏“开机自启动”和“异常崩溃自动拉起”的能力。在现代主流 Linux 系统(如 Ubuntu 20.04+、Debian 11+、CentOS 7+、Rocky Linux)中,使用 systemd 是最严谨的工业级方案。

1. 编写 Unit 服务配置文件

以管理员权限在 /etc/systemd/system/ 目录下创建配置文件,例如 my_script.service:

# /etc/systemd/system/my_script.service
[Unit]
Description=Python 自动化后台守护任务
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/project
Environment=PYTHONUNBUFFERED=1
# 必须使用绝对路径指定 Python 解释器(支持虚拟环境)与脚本位置
ExecStart=/home/ubuntu/project/venv/bin/python3 -u /home/ubuntu/project/script.py
Restart=always
RestartSec=5s
StandardOutput=append:/home/ubuntu/project/logs/app.log
StandardError=append:/home/ubuntu/project/logs/app.log

[Install]
WantedBy=multi-user.target

2. 服务常用管理指令

# 重载 systemd 配置文件
sudo systemctl daemon-reload

# 启动服务
sudo systemctl start my_script

# 设置开机自启动
sudo systemctl enable my_script

# 查看运行状态及最近日志
sudo systemctl status my_script

# 实时查看由 systemd 收集的日志流
sudo journalctl -u my_script -f

六、交互式长任务方案:tmux 终端复用器

如果运行的 Python 脚本在执行过程中可能需要人工输入参数确认,或者需要随时恢复图形化控制台进度条(如 tqdm),nohup 无法提供交互会话的重新接入。此时使用 tmux 是最理想的选择。

tmux 允许用户在服务器端建立一个与本地 SSH 彻底解耦的虚拟会话。即使用户断开网络,会话依然在云端后台活跃,并且可以结合 tee 命令一边在屏幕观察一边写盘:

# 1. 创建并进入名为 task 的专属 tmux 会话
tmux new -s task

# 2. 在 tmux 窗口中启动脚本,使用 tee 同时输出到屏幕与文件
python3 -u script.py 2>&1 | tee -a app.log

# 3. 按键盘快捷键 Ctrl + B,随后松开并单按 D 键,安全分离(Detach)会话返回母机终端
# 此时已可以安全关闭 SSH 连接

# 4. 重新连接 SSH 后,随时恢复进入该会话:
tmux attach -t task

七、后台运行四大方案选型对比

根据任务的生命周期、容错要求以及管理权限,下表整理了主流方案的技术特性与选型依据:

Linux后台运行Python脚本并保存日志的方法
图 5:Linux 后台运行 Python 任务的四大技术方案选型决策图
方案名称 适用场景 开机自启 崩溃恢复 操作复杂度
nohup + & 单次执行、快速测试、临时爬虫、排查脚本 否 无(退出即终止) 极低(单行命令)
tmux / screen 交互式脚本、需频繁重连看控制台进度条、多窗调试 否 无 低(需熟悉快捷键)
systemd 服务 生产业务、核心守护进程、API 服务、MQ 消费者 是 高(毫秒级自拉起) 中等(需 root 配置)
Supervisor 多 Python 脚本批量编排、普通用户权限下的进程守护 依赖系统服务 高(应用级守护) 中等(需配置 ini)

八、生产环境运行的五项避坑法则

为了保证后台任务长期稳定运行,不因外部路径变动或磁盘耗尽产生隐患,请务必在部署时遵守以下规范:

  1. 一律使用绝对路径:后台任务脱离了用户的当前终端上下文,如果脚本内依赖相对路径读取配置(如 ./config.json),在某些场景下其工作路径可能漂移到系统根目录导致 FileNotFoundError。建议脚本代码内部通过 os.path.dirname(os.path.abspath(__file__)) 锁定基准路径;
  2. 使用虚拟环境的独立解释器:避免在命令中直接使用全局的 python3。建议指定明确的虚拟环境解释器完整路径,例如 /data/venv/bin/python3,防止系统更新全局包时引发依赖破坏;
  3. 警惕日志无限制膨胀:长时间运行的高吞吐量脚本很容易产生几十 GB 的巨大日志,进而占满服务器磁盘 inodes 或存储空间。应结合系统 logrotate 工具对 app.log 进行定时归档、压缩与清理;
  4. 确认进程独占性:在通过 nohup 重新拉起程序前,务必先用 ps aux | grep script.py 检查旧版本是否仍在运行,避免出现两个进程同时读写相同资源或并发冲突;
  5. 优先使用 SIGTERM 退出:在编写 Python 代码时,建议注册 signal.signal(signal.SIGTERM, handler) 信号监听回调,以便在被运维管理工具停止时,能够安全提交事务并关闭数据库连接池。
相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表