journalctl是唯一能回溯真实启动行为的工具,它捕获systemd调度全过程,可精准定位服务是否被尝试启动、依赖是否满足、单元是否被masked或配置错误,并支持-b参数限定本次启动上下文。

开机启动项日志无输出,不是脚本没跑,而是系统压根没执行、或执行了但被静默吞掉。关键不在“看不看得到”,而在“有没有发生过”。journalctl 是唯一能回溯真实启动行为的工具,它不依赖脚本自己打日志,而是捕获 systemd 调度全过程。
确认服务是否真正被 systemd 尝试启动
很多“没反应”其实是根本没触发——可能因为依赖未满足、单元被 masked、或配置语法错误导致加载失败。
- 运行 sudo systemctl list-units --type=service --state=failed,看你的服务是否出现在失败列表里(哪怕只失败一次)
- 用 sudo systemctl cat your-service.service 检查 service 文件是否被正确加载,有无语法报错(比如 Unit section 缺失、ExecStart 路径不存在)
- 检查是否被屏蔽:systemctl is-enabled your-service.service 返回 disabled 或 masked 都会导致完全跳过启动
用 journalctl 锁定本次启动的完整执行链
别查“所有日志”,要精准定位“这次开机”的上下文。重点看三个时间点:服务启动前、启动中、启动后。
- 查本次启动中该服务的全部记录:journalctl -u your-service.service -b
- 如果连 -u 都没输出,说明 systemd 根本没加载这个单元,改查全局启动流:journalctl -b | grep -i "your-service\|failed\|start"
- 同步看它的依赖项是否就绪,比如网络:journalctl -u network.target -b 或 journalctl -u multi-user.target -b
排查环境与路径静默失败的典型陷阱
脚本退出码为 0 但什么都没做,往往是因为环境缺失或路径失效,而 systemd 默认不报错。
- 确保 ExecStart 使用绝对路径:/usr/bin/python3 /opt/app/main.py,而不是 python main.py
- 添加 Environment=PATH=/usr/local/bin:/usr/bin:/bin,避免找不到命令
- 在 ExecStart 前加 Type=oneshot 和 RemainAfterExit=yes(适用于初始化类脚本),防止 systemd 因进程退出太快误判失败
- 若脚本依赖用户环境变量(如 $HOME、$VIRTUAL_ENV),必须显式声明:Environment="HOME=/home/user" "VIRTUAL_ENV=/opt/venv"
验证 rc.local 兼容层是否生效(仅限旧系统)
Ubuntu 16.04 或某些嵌入式系统仍用 /etc/rc.local,但它在 systemd 下是伪装成服务运行的,容易被忽略。
- 检查状态:sudo systemctl status rc-local,看是否 active 或 failed
- 确认文件权限:sudo ls -l /etc/rc.local 必须含 x 权限,且首行是 #!/bin/sh(不是 #!/bin/bash)
- 最后一行必须是 exit 0,前面不能有空行,否则脚本提前终止
- 查看其日志:sudo journalctl -u rc-local -b


















