超详细图文教程:Ubuntu 18.04设置开机运行Shell
你是不是也遇到过这样的问题:在Ubuntu 18.04上写好了shell脚本,想让它开机自动运行,却发现/etc/rc.local文件根本不起作用?点开终端试了又试,重启后脚本还是没执行——别急,这不是你的操作错了,而是Ubuntu 18.04默认禁用了这个传统机制。
这背后的原因其实很清晰:Ubuntu 18.04全面转向systemd服务管理,而旧版的rc.local依赖于SysV init兼容层,系统默认不启用它。但好消息是,不用重装系统、不用换发行版、也不用学复杂的服务单元语法,只要6个清晰步骤,就能让rc.local重新工作,稳稳当当地帮你跑起自定义脚本。
本文全程基于真实环境验证(Ubuntu 18.04.6 LTS,内核5.4.0-150-generic),所有命令可直接复制粘贴,每一步都附带关键说明和避坑提示。无论你是刚接触Linux的新手,还是习惯用Ubuntu 14/16的老用户,都能照着做成功。
1. 为什么Ubuntu 18.04的rc.local不生效?
1.1 系统机制变化的本质
在Ubuntu 14.04及更早版本中,系统启动流程由SysV init控制,/etc/rc.local是标准的“兜底执行入口”——只要文件存在且有执行权限,它就会在多用户模式最后被调用。
而Ubuntu 18.04采用systemd作为默认init系统。systemd本身不原生支持rc.local,它需要一个“适配器服务”来桥接这个老机制。这个适配器就是rc-local.service,但它默认未安装、未启用、未激活。
关键理解:不是
rc.local被删除或废弃了,而是它变成了一位“待岗员工”——得先给它发工牌(创建service文件)、签劳动合同(启用服务)、再打卡上班(启动服务),它才能干活。
1.2 常见误判与排查信号
如果你尝试过直接编辑/etc/rc.local却失败,大概率会看到以下现象:
- 手动执行
sudo /etc/rc.local能成功,但重启后无任何效果 systemctl status rc-local显示Unit rc-local.service could not be found/var/log/syslog里找不到rc.local相关日志ls -l /etc/rc.local显示权限为-rw-r--r--(缺少可执行位)
这些都不是脚本写错了,而是systemd层面的“准入机制”还没打通。接下来,我们就一步步把它建起来。
2. 创建rc-local.service服务单元
2.1 新建systemd服务配置文件
打开终端,执行以下命令创建服务定义文件:
sudo vim /etc/systemd/system/rc-local.service说明:路径
/etc/systemd/system/是systemd用户级服务的标准存放位置,放在这里的服务能被systemctl直接识别和管理。
2.2 输入完整服务配置内容
将下方内容逐字复制进文件(注意大小写和空格):
[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逐项解析(小白友好版):
Description:服务的中文描述,便于你日后识别ConditionPathExists:告诉systemd——只有/etc/rc.local这个文件真实存在,才允许启动本服务Type=forking:声明这是一个“后台守护进程式”服务(传统rc.local的运行方式)ExecStart:真正要执行的命令——运行/etc/rc.local startTimeoutSec=0:禁止超时中断,避免脚本执行时间稍长就被杀掉RemainAfterExit=yes:关键!表示即使rc.local执行完了,也认为服务仍处于“活跃”状态,确保后续依赖它的服务能正常启动WantedBy=multi-user.target:定义服务启动时机——在系统进入标准多用户模式(即你日常使用的图形或命令行界面)时触发
保存并退出(vim中按Esc,输入:wq回车)。
3. 编写并配置/etc/rc.local脚本
3.1 创建rc.local主文件
执行命令新建文件:
sudo vim /etc/rc.local3.2 填入标准模板并添加你的逻辑
将以下内容完整粘贴进去(请勿删除注释行,它们是systemd识别脚本合法性的依据):
#!/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是必须的,它指定解释器为POSIX shell,并开启“出错即停”模式(-e)exit 0是强制要求——systemd把返回值0当作“执行成功”,否则会标记服务为失败echo ... > /usr/local/test.log是一行验证代码,用于确认脚本是否真被调用
保存退出。
3.3 设置可执行权限
sudo chmod +x /etc/rc.local为什么必须加x权限?
systemd在启动服务时,会严格检查ExecStart指向的文件是否具备执行权限。没有x位,连第一步都迈不出去。
4. 启用并启动rc-local服务
4.1 启用服务(开机自启)
sudo systemctl enable rc-local效果:该命令会在
/etc/systemd/system/multi-user.target.wants/目录下创建一个指向rc-local.service的软链接。这意味着每次系统启动到多用户模式时,systemd都会自动加载并尝试启动它。
4.2 立即启动服务(无需重启)
sudo systemctl start rc-local.service注意:命令末尾的
.service可以省略,但显式写出更清晰,避免与其他同名unit混淆。
4.3 检查服务状态(关键验证步骤)
sudo systemctl status rc-local.service成功状态应显示:
Active: active (exited)或active (running)Loaded: loaded (/etc/systemd/system/rc-local.service; enabled; vendor preset: enabled)- 最后几行有类似
Started /etc/rc.local Compatibility的日志
如果看到failed或inactive,请立即执行下一步排查。
5. 验证执行结果与常见问题排查
5.1 检查日志输出
cat /usr/local/test.log预期输出:
看到这行字,说明添加自启动脚本成功。出现这句话,证明rc.local已成功被systemd调用。
5.2 重启系统进行终极验证
sudo reboot等待系统完全启动后,再次执行:
cat /usr/local/test.log如果内容依然存在,恭喜你——基础环境已100%打通。
5.3 高频报错与解决方案
| 报错现象 | 根本原因 | 解决方法 |
|---|---|---|
Failed to start rc-local.service: Unit rc-local.service not found | service文件名错误(如写成rc_local.service)或路径不对 | 检查文件是否在/etc/systemd/system/下,且名为rc-local.service(含短横线) |
Job for rc-local.service failed | rc.local中某行命令执行失败(如路径不存在、权限不足) | 运行sudo journalctl -u rc-local.service -n 50 --no-pager查看详细错误日志 |
rc.local执行了但test.log为空 | 脚本中缺少exit 0,或echo命令被重定向失败 | 确保最后一行是exit 0;检查/usr/local/目录是否存在(可用sudo mkdir -p /usr/local创建) |
| 中文字符导致脚本崩溃 | Ubuntu 18.04默认locale可能不支持UTF-8中文 | 在rc.local顶部添加export LANG=en_US.UTF-8,或改用英文提示 |
实用技巧:调试阶段,可在
rc.local中加入时间戳日志,例如:date >> /var/log/rclocal.log
这样每次启动都会记录时间,方便确认是否真的被执行。
6. 将rc.local作为“启动调度中心”(进阶用法)
现在你已经拥有了一个稳定可靠的启动入口。但直接在rc.local里写业务逻辑并不优雅——它更适合扮演“总指挥”的角色,把具体任务分发给独立的脚本文件。这样做有三大好处:
业务脚本与系统配置解耦,修改不影响核心机制
多个任务可并行或按需组织,结构更清晰
单个脚本出错不会导致整个启动链路中断
6.1 创建独立业务脚本(以Python为例)
假设你想开机自动运行一个Python程序ce.py,步骤如下:
第一步:创建Python脚本
sudo vim /home/ubuntu/ce.py填入内容:
with open("/home/ubuntu/sb.txt", "w") as f: f.write("SB")注意路径:务必使用绝对路径(如
/home/ubuntu/sb.txt),因为开机时当前工作目录不确定。
第二步:创建调用它的Shell脚本
sudo vim /home/ubuntu/test.sh填入内容:
#!/bin/bash cd /home/ubuntu/ python3 ce.py exit 0关键点:
- 显式使用
python3而非python(Ubuntu 18.04默认无python命令指向)cd切换到脚本所在目录,避免相对路径失效- 末尾
exit 0不可省略
第三步:赋予执行权限
sudo chmod +x /home/ubuntu/test.sh6.2 修改rc.local调用外部脚本
编辑/etc/rc.local:
sudo vim /etc/rc.local将原来的echo行替换为:
/home/ubuntu/test.sh exit 0重要提醒:不要加
sudo前缀!rc.local本身以root权限运行,加sudo反而会导致权限冲突。
保存后,重启验证——/home/ubuntu/sb.txt文件将如期生成。
7. 总结:一条安全、稳定、可维护的启动路径
回顾整个过程,我们没有改动系统底层,没有绕过systemd规范,而是尊重Ubuntu 18.04的设计哲学,用标准方式激活了一个被遗忘的经典机制。这套方案的价值在于:
- 零风险:所有操作仅新增配置文件,不影响现有服务
- 强兼容:未来升级到Ubuntu 20.04/22.04,此方法依然有效(已实测验证)
- 易维护:业务逻辑全部集中在
/home/ubuntu/等用户目录,rc.local保持极简 - 好排查:每个环节都有明确的状态检查点(
systemctl status、journalctl、日志文件)
你现在拥有的不仅是一个能开机运行的脚本,而是一套可扩展的自动化基础设施。无论是定时备份、服务监控、数据同步,还是AI模型常驻推理,都可以通过这个入口无缝接入。
下一步,你可以尝试:
🔹 把多个.sh脚本按顺序写入rc.local,实现启动流水线
🔹 结合systemd timer实现周期性任务,替代老旧的cron
🔹 为关键脚本添加健康检查,失败时自动告警
技术从来不是目的,而是让想法落地的杠杆。你已经握住了最稳妥的那一端。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。