@reboot是轻量级启动自启动的首选方案,适用于单次执行、无依赖、无守护的脚本;环境变量需要用绝对路径和显式声明(如home)、PATH),不支持自动重启,日志需要重定向调查。
现代Linux系统(Ubuntu 22.04+、CentOS 7+、Debian 10+)下,直接往 /etc/rc.local 里加 python3 /path/to/script.py & 已经基本不可靠了——环境变量丢失,网络未就绪,无崩溃重启,日志难查,90% 所有的失败都来自于此。 真正能落地的方案只有两个:systemd 服务(首选生产)和 crontab @reboot(轻量级备选),其他方法要么过时,要么维护成本高。
[Unit] 和 [Service]
systemd 不是“执行命令”,而是根据依赖关系调度服务。写错关键字段会导致脚本启动失败或无声退出。
-
After=network.target必须明确声明,否则脚本在网卡起床前就会运行,requests或socket操作全报ConnectionRefusedError -
User=不能省略字段。使用 root 运行有安全风险;使用普通用户时,WorkingDirectory=必须设置为用户有读写权限的路径,否则open()写日志会 PermissionDenied -
Environment="PATH=..."是 conda/virtualenv 用户的救命字段。不加此行,conda activate myenv在 service 里面根本找不到命令,ExecStart直接报Command not found -
RestartSec=5建议设为 5 超过几秒钟。太快的重启可能会触发 systemd 速度限制导致服务受到限制start-limit-hit锁死
最小可用配置示例(存为 /etc/systemd/system/myscript.service):
[Unit] Description=Data collector daemon After=network.target [Service] Type=simple User=pi WorkingDirectory=/home/pi/scripts Environment="PATH=/home/pi/miniconda3/envs/collector/bin:/usr/local/bin:/usr/bin:/bin" ExecStart=/home/pi/miniconda3/envs/collector/bin/python /home/pi/scripts/collector.py Restart=always RestartSec=10 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.targetcrontab @reboot:什么场景适合?如何避免“执行但无效”?
@reboot 本质是用户级定时任务,不依赖 systemd,脚本适用于单次启动、无依赖、无过程保护(如初始配置、发送通知、备份快照)。但它没有生命周期管理的服务水平。
立即学习“Python免费学习笔记(深入);
在Linux系统下,shell编程入门文章 中文WORD版
本文主要讲述了Linux系统下的Shell编程介绍;Shell编程具有许多类似C语言和其他程序语言的特点,但不像编程语言那么复杂。Shell程序是一系列Linux命令和实用程序,放置在文件中。执行时,每个命令都通过Linux一个接一个地解释和执行。感兴趣的朋友可以来看看
下载- 绝对路径必须完整:
@reboot /usr/bin/python3 /home/user/backup.py > /tmp/backup.log 2>&1——python3不能只写python,因为 cron 的 PATH 极简,which python结果很可能无效 - 默认情况下,环境变量为空。假如脚本依赖于脚本
$HOME或者自定义变量,必须在 crontab 内显式导出:@reboot HOME=/home/user /usr/bin/python3 ... - 它开机时只跑一次。脚本中途崩溃不会重拉,也不会重拉
Restart=机制。不要用它跑 long-running 的 Web server 或采集 daemon - 调试时用
sudo -u user bash -c 'env | grep -E "^(HOME|PATH)"'模拟 cron 环境比猜测快得多
systemctl status 以后该看什么
systemctl status myscript 只显示最后几行状态,真正的问题往往隐藏在 journal 日志里。
- 实时输出:
journalctl -u myscript -f(-f表示 follow,像tail -f) - 查看所有历史日志:
journalctl -u myscript --since "2026-07-01 10:00:00",配合脚本里print()或logging.info()定位时间点 - 常见的错误模式:
-
Failed at step EXEC spawning→ExecStart路径错,或 Python 解释器无权执行 -
code=exited, status=1/FAILURE→ 脚本第一行抛异常,比如 import 配置文件不存在失败 -
start-limit-hit→ 10 几秒钟内连续崩溃 5 次,systemd 主动停服。首先sudo systemctl reset-failed myscript,再次检查日志的根因
-
- 脚本自己加日志比依赖 systemd 更可靠:
logging.basicConfig(filename='/var/log/myscript.log', level=logging.INFO),避免 journal 被轮转清空
ExecStart 里写 source 或 conda activate
systemd service 的 shell 是 /bin/sh,不支持 source,也不认识 conda activate 命令-它只在 bash 里注册了 alias/function。
- 正确的做法:使用 conda 环境里的 Python 解释器的绝对路径,比如
/home/user/miniconda3/envs/myenv/bin/python - 或者,在
[Service]中用ExecStart=/bin/bash -c 'source /etc/profile.d/conda.sh && conda activate myenv && exec python /path/script.py',但必须加exec,否则 bash 过程会卡住,systemd 认为服务还没有真正启动 - 更安全的是把 conda 环境包装成可执行脚本:
conda env export > environment.yml,部署时用conda env create -f environment.yml,确保解释器路径稳定
最容易被忽视的一点:systemd 默认不读用户的 ~/.bashrc 或 /etc/environment,所有路径,变量、激活逻辑是显式写入的 service 没有写在文件里,就是不存在。