真实体验分享:成功实现开机写入日志到test.log
1. 背景与目标
最近在部署一个自动化任务时,遇到了一个常见但关键的问题:如何让系统在每次开机时自动执行一段脚本,并将运行结果记录到指定的日志文件中。我的目标非常明确——实现开机自动写入一条日志信息到/usr/local/test.log文件中。
听起来很简单,但在 Ubuntu 18.04 及更高版本中,传统的rc.local方式默认已经被弃用。很多老教程不再适用,稍有不慎就会导致服务启动失败或系统卡住。本文将完整还原我从尝试、报错到最终成功的全过程,不跳过任何一个细节,适合和我一样想“稳稳落地”的朋友。
2. 为什么不能直接用 rc.local?
2.1 版本变化带来的兼容性问题
Ubuntu 从 16.04 开始逐步迁移到systemd作为初始化系统,到了 18.04 后,/etc/rc.local已经不再默认启用。即使你创建了这个文件,它也不会被执行,除非你手动配置相应的 systemd 服务来兼容它。
这就是为什么很多人发现:
- 写好了
/etc/rc.local - 给了可执行权限
- 重启后却发现什么都没发生
根本原因:systemd 根本没去调用它。
3. 解决方案:通过 systemd 恢复 rc.local 功能
我们不是要绕开 systemd,而是要“借它的力”,让它知道:请在开机时执行/etc/rc.local这个脚本。
3.1 创建 rc-local.service 服务单元
第一步是告诉 systemd:“我想用 rc.local,请为它注册一个服务”。
运行命令创建服务文件:
sudo vim /etc/systemd/system/rc-local.service然后将以下内容粘贴进去:
[Unit] Description=/etc/rc.local Compatibility ConditionPathExists=/etc/rc.local [Service] Type=forking ExecStart=/etc/rc.local start TimeoutSec=0 StandardOutput=tty RemainAfterExit=yes SysVStartPriority=99 [Install] WantedBy=multi-user.target关键参数说明:
ConditionPathExists=/etc/rc.local:只有当/etc/rc.local存在时才启动该服务Type=forking:表示脚本会 fork 子进程后退出主进程(符合传统 SysVinit 行为)RemainAfterExit=yes:即使脚本执行完毕,也认为服务仍在运行(因为是开机一次性任务)WantedBy=multi-user.target:在多用户模式下启动,也就是正常开机状态
3.2 创建并配置 /etc/rc.local 脚本
接下来创建实际要执行的脚本文件:
sudo vim /etc/rc.local输入以下内容:
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. echo "看到这行字,说明添加自启动脚本成功。" > /usr/local/test.log exit 0注意点:
- 必须以
#!/bin/sh -e开头,-e表示遇到错误立即退出- 最后一定要有
exit 0,否则 systemd 会认为脚本未正常结束- 日志路径
/usr/local/test.log需要确保目录存在且可写
保存退出后,赋予可执行权限:
sudo chmod +x /etc/rc.local3.3 启用并启动 rc-local 服务
现在让 systemd 加载我们的新服务:
sudo systemctl enable rc-local这条命令的作用是:设置开机时自动启动该服务。
接着,我们可以手动先启动一次,看看是否能立即生效:
sudo systemctl start rc-local.service检查服务状态:
sudo systemctl status rc-local.service如果一切顺利,你会看到类似这样的输出:
● rc-local.service - /etc/rc.local Compatibility Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled) Active: active (exited) since Mon 2025-04-05 10:20:12 CST; 1min ago重点看两点:
Loaded: ... enabled:表示已启用Active: active (exited):表示已成功执行并退出
3.4 验证日志是否生成
执行完服务后,查看日志文件是否存在:
cat /usr/local/test.log你应该能看到输出:
看到这行字,说明添加自启动脚本成功。恭喜!你已经完成了最关键的一步:让系统在当前会话中成功执行了 rc.local 脚本。
4. 重启验证:真正的“开机自启”测试
前面只是手动启动了一次服务,真正的考验是——重启之后还能不能自动写入日志?
执行重启:
sudo reboot等待系统重新启动完成后,再次查看日志文件:
cat /usr/local/test.log如果你仍然能看到那句话,那就说明: 开机自启成功
日志写入成功
rc.local 被正确执行
5. 常见问题排查指南
尽管流程看似简单,但我第一次尝试时也失败了。以下是我在实践中遇到的真实问题及解决方案。
5.1 服务状态显示 failed
运行systemctl status rc-local.service显示:
Active: failed (Result: exit-code)可能原因:
/etc/rc.local没有exit 0- 脚本中有语法错误
- 目标路径不可写(如
/usr/local权限不足)
解决方法: 检查日志:
journalctl -u rc-local.service --since "1 hour ago"你会看到具体的错误信息,比如:
/etc/rc.local: 10: cannot create /usr/local/test.log: Permission denied这就说明权限有问题。可以尝试改用/tmp/test.log测试,或者确保/usr/local目录对 root 可写(通常没问题)。
5.2 中文字符导致脚本执行失败
这是我踩过的一个坑!
虽然 Linux 支持 UTF-8,但某些环境下,/etc/rc.local中包含中文会导致 systemd 执行失败。
比如这句:
echo "看到这行字,说明添加自启动脚本成功。" > /usr/local/test.log如果系统 locale 设置不完整,可能会报错。
建议临时改为英文测试:
echo "Startup script executed successfully." > /usr/local/test.log确认功能正常后再换回中文,并确保系统语言环境配置正确。
5.3 rc-local.service 无法启用
运行systemctl enable rc-local报错:
Failed to enable unit: File /etc/systemd/system/rc-local.service already exists.说明服务文件已存在,可能是之前创建重复了。可以先删除再重试:
sudo rm /etc/systemd/system/rc-local.service然后再重新创建。
6. 进阶用法:用 rc.local 启动自定义脚本
上面的例子只是写一行日志,实际工作中我们更希望开机时运行自己的程序,比如 Python 脚本、Shell 脚本等。
下面演示如何通过rc.local调用外部脚本。
6.1 创建测试用的 Python 脚本
假设我们要在开机时运行一个 Python 脚本,向文件写入内容。
先创建脚本目录:
cd /home/lbw/创建ce.py:
with open("sb.txt", "w") as f: f.write("SB")注意:这个脚本会在当前目录下生成sb.txt文件。
6.2 创建启动脚本 test.sh
为了方便管理,我们不直接在rc.local里写复杂命令,而是让它调用一个独立的.sh脚本。
创建test.sh:
sudo vim /home/lbw/test.sh内容如下:
#!/bin/bash cd /home/lbw/ python ce.py exit 0赋予执行权限:
sudo chmod +x /home/lbw/test.sh6.3 修改 rc.local 调用外部脚本
编辑/etc/rc.local:
sudo vim /etc/rc.local修改为:
#!/bin/sh -e # 调用自定义脚本 /home/lbw/test.sh exit 0这样做的好处是:
rc.local保持简洁- 复杂逻辑放在外部脚本中,便于调试
- 更容易扩展多个任务
6.4 重启验证效果
再次重启系统:
sudo reboot登录后检查/home/lbw/sb.txt是否生成:
cat /home/lbw/sb.txt如果看到输出SB,说明: Python 脚本被成功调用
自定义 Shell 脚本被执行
整个链路打通
7. 最佳实践与建议
经过这次完整的实践,我总结出几点实用建议,帮助你少走弯路。
7.1 推荐使用“索引式”rc.local
不要把所有逻辑都塞进/etc/rc.local,而是把它当作一个“启动入口”,只负责调用其他脚本。
例如:
#!/bin/sh -e # 启动数据同步脚本 /opt/scripts/start-sync.sh # 启动监控服务 /usr/local/bin/start-monitor.sh # 初始化网络配置 /etc/network/init-network.sh exit 0这种方式更清晰、易维护。
7.2 使用绝对路径
在rc.local和被调用脚本中,尽量使用绝对路径,避免因$PATH或工作目录不同而导致命令找不到。
错误示例:
python ce.py # 可能找不到 python 或 ce.py正确做法:
/usr/bin/python3 /home/lbw/ce.py7.3 添加日志记录以便调试
可以在脚本开头加一句时间戳日志,方便判断是否执行:
echo "$(date): Starting startup script..." >> /var/log/startup.log这样即使主任务失败,也能通过日志确认执行时间。
7.4 注意文件权限和用户上下文
rc.local是以 root 身份运行的,所以:
- 创建的文件属于 root
- 如果你的应用需要普通用户权限运行,记得用
su - username -c 'command'
例如:
su - lbw -c '/usr/bin/python3 /home/lbw/ce.py'8. 总结
通过本次真实环境下的操作与排错,我们成功实现了“开机写入日志到test.log”的目标,并进一步扩展到了运行自定义脚本的能力。
回顾整个过程的关键步骤:
1. 创建rc-local.service兼容单元
2. 编写并授权/etc/rc.local脚本
3. 启用并测试rc-local.service
4. 重启验证日志生成
5. 排查常见问题(权限、中文、路径等)
6. 扩展至调用外部脚本(Shell + Python)
这套方法适用于绝大多数基于 systemd 的 Linux 发行版(如 Ubuntu 18.04+、Debian 10+、CentOS 7+),具有良好的通用性和稳定性。
只要记住一句话:在现代 Linux 中,想用rc.local,就必须先给它配一个 systemd 服务。
掌握了这一点,你就拥有了一个简单而强大的开机自启工具。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。