news 2026/4/21 14:12:16

手把手教你配置/etc/rc.local,让脚本随系统启动

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手教你配置/etc/rc.local,让脚本随系统启动

手把手教你配置/etc/rc.local,让脚本随系统启动

你是不是也遇到过这样的问题:写好了自动化脚本,每次重启后却要手动运行?或者部署了一个后台服务,总得登录服务器再敲一遍命令?其实,Linux系统早就为你准备好了“开机自动执行”的能力——通过/etc/rc.local文件就能轻松实现。但很多新手会发现,在较新版本的 Ubuntu(比如 18.04 及之后)上,直接编辑/etc/rc.local并不能生效。这不是你的脚本有问题,而是系统启动机制变了。

别担心,这不是功能被删掉了,只是换了一种更规范、更可控的方式启用它。本文不讲抽象原理,不堆术语,就用最直白的语言、最完整的步骤、最容易复现的操作,带你从零开始配置好rc.local,让它真正“随系统一起醒来”。无论你是刚接触 Linux 的运维新人,还是需要快速落地一个自启任务的开发者,只要照着做,15 分钟内就能看到/usr/local/test.log里那行成功的提示。

全文基于真实环境验证(Ubuntu 22.04 LTS),所有命令可直接复制粘贴,每一步都说明“为什么这么做”和“不做会怎样”,还会提前告诉你几个新手踩过的坑——比如中文路径报错、权限遗漏、服务状态误判等。现在,我们就开始吧。

1. 为什么 /etc/rc.local 默认不工作了?

在 Ubuntu 16.04 之前,系统使用传统的 SysV init 启动方式,/etc/rc.local是一个被默认加载的“万能启动入口”。但从 Ubuntu 16.04 开始,系统全面转向 systemd,而 systemd 默认不再主动读取或执行 rc.local。它不是被删除了,而是被“雪藏”了——就像一个老工具被收进抽屉,需要你亲手拿出来、擦干净、装上手柄,才能继续用。

所以,你编辑了/etc/rc.local却没反应,并不是脚本写错了,而是 systemd 根本没去调用它。解决办法很简单:告诉 systemd,“请把这个旧文件当作一个正式服务来管理”。

这个过程只需要两步核心操作:

  • 创建一个 systemd 服务单元文件(rc-local.service),定义如何运行 rc.local;
  • 确保/etc/rc.local本身存在、可执行、且内容规范。

下面我们就一步步完成这两件事。

2. 创建并配置 rc-local.service 服务单元

systemd 通过.service文件来定义服务行为。我们要创建一个专门用于兼容rc.local的服务,让它在多用户模式下自动启动。

2.1 创建服务文件

打开终端,执行以下命令创建服务定义文件:

sudo vim /etc/systemd/system/rc-local.service

小提示:如果你不熟悉 vim,可以用sudo nano /etc/systemd/system/rc-local.service替代,nano 更易上手。

将以下完整内容粘贴进去(注意逐字复制,包括空行和缩进):

[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

2.2 关键字段说明(不用死记,看懂就行)

  • ConditionPathExists=/etc/rc.local:表示只有当/etc/rc.local文件真实存在时,这个服务才允许启动。这是安全机制,避免服务找不到目标文件而报错。
  • Type=forking:告诉 systemd,这个脚本会“派生子进程”(即自己启动后就退出,把任务交给后台进程)。这是传统 rc.local 的典型行为。
  • ExecStart=/etc/rc.local start:明确指定执行命令。注意这里带了start参数,是因为老式 rc.local 脚本通常支持start/stop等参数。
  • RemainAfterExit=yes:最关键的一行。它让 systemd 认为:即使/etc/rc.local执行完了、进程退出了,这个服务“依然处于运行状态”。否则 systemd 会立刻标记服务为“已停止”,后续依赖它的服务可能出错。
  • WantedBy=multi-user.target:表示该服务应在标准的多用户命令行模式下启动(也就是你日常使用的非图形界面状态)。

这一步完成后,systemd 就知道了“有这么一个服务,它负责运行 rc.local”,但还缺一个真正的rc.local文件。

3. 创建并初始化 /etc/rc.local 文件

现在我们来创建那个被 systemd 监控的“启动索引文件”。

3.1 创建空白文件并添加基础模板

执行命令:

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

3.2 为什么必须包含这些内容?

  • #!/bin/sh -e:声明这是 shell 脚本,且-e表示“任一命令失败则立即退出”,防止错误被忽略。
  • exit 0绝对不能省略。systemd 依赖这个返回值判断脚本是否成功执行。如果忘了写,服务状态会显示failed,即使日志看起来正常。
  • echo ... > /usr/local/test.log:这是我们的“心跳检测”。它会在/usr/local/test.log中写入一行文字,方便你重启后快速验证是否真的生效。

3.3 设置可执行权限

Linux 不会执行没有“执行权限”的文件。必须显式赋予:

sudo chmod +x /etc/rc.local

正确做法:chmod +x
常见错误:只改了内容,忘了加权限,结果服务启动失败。

4. 启用并启动 rc-local 服务

现在,systemd 已经认识这个服务,rc.local文件也准备就绪。接下来就是“通电开机”的最后一步。

4.1 启用服务(开机自启)

让 systemd 在每次启动时自动加载这个服务:

sudo systemctl enable rc-local

这条命令的本质,是创建一个软链接:
/etc/systemd/system/multi-user.target.wants/rc-local.service → /etc/systemd/system/rc-local.service
这样,系统一进入multi-user.target,就会顺带启动它。

4.2 立即启动服务(无需重启)

你可以马上测试效果,不用等重启:

sudo systemctl start rc-local.service

4.3 检查服务状态

运行以下命令查看是否成功:

sudo systemctl status rc-local.service

成功状态特征

  • 第一行显示active (exited)active (running)(取决于RemainAfterExit设置)
  • 最后几行有Started /etc/rc.local Compatibility
  • 没有红色的failederror字样

常见失败原因

  • /etc/rc.local没有+x权限 → 运行sudo chmod +x /etc/rc.local
  • 文件里漏了exit 0→ 用sudo vim /etc/rc.local补上
  • 脚本里有语法错误(比如中文引号、未闭合括号)→ 用sudo bash -n /etc/rc.local检查语法

确认状态正常后,再检查日志文件:

cat /usr/local/test.log

如果输出看到这行字,说明添加自启动脚本成功。,恭喜,你的rc.local已经活过来了。

5. 把真正想运行的脚本“挂”进 rc.local

现在rc.local是个空壳,它只负责执行自己内部的几行命令。但我们的目标是:让它成为所有自启任务的统一入口。就像一个总开关,按下它,就自动打开你家所有的灯。

5.1 创建你自己的业务脚本(以 Python 为例)

假设你想开机自动运行一个 Python 程序ce.py,它会在当前目录生成一个sb.txt文件。

先创建存放脚本的目录(推荐放在/opt/usr/local/bin,避免权限问题):

sudo mkdir -p /opt/mystartup cd /opt/mystartup

创建 Python 脚本:

sudo vim ce.py

内容如下(注意:不要用中文路径,不要在脚本里写中文注释或字符串,除非你明确设置了 UTF-8 环境):

with open("/opt/mystartup/sb.txt", "w") as f: f.write("SB")

再创建一个 shell 包装器test.sh,用来调用 Python:

sudo vim test.sh

内容:

#!/bin/bash cd /opt/mystartup python3 ce.py exit 0

重要提醒

  • 使用python3而不是python,避免因系统默认 Python 版本不一致导致失败;
  • cd切换到脚本所在目录,确保相对路径正确;
  • 同样必须以exit 0结尾。

赋予执行权限:

sudo chmod +x ce.py test.sh

5.2 修改 rc.local,调用你的脚本

编辑/etc/rc.local

sudo vim /etc/rc.local

把原来的echo行替换成调用你脚本的命令(放在exit 0之前):

#!/bin/sh -e # ...(前面的注释保持不变) # 在这里添加你的启动命令 /opt/mystartup/test.sh exit 0

保存退出。再次确认权限:

sudo chmod +x /etc/rc.local

5.3 重新加载并测试

因为修改了服务定义文件,需要通知 systemd 重载配置:

sudo systemctl daemon-reload

然后重启服务:

sudo systemctl restart rc-local.service

检查是否成功:

sudo systemctl status rc-local.service cat /opt/mystartup/sb.txt

如果sb.txt里出现了SB,说明你的 Python 脚本已成功随系统启动。

6. 排查常见问题的实用技巧

即使严格按照步骤操作,也可能遇到意外。以下是几个高频问题和对应解法,帮你少走弯路。

6.1 服务状态显示 active but failed

运行sudo systemctl status rc-local.service后,看到active (exited)但紧接着又出现failed,大概率是rc.local内部某条命令执行出错,但脚本仍返回了 0。

解决方法
临时关闭-e选项,让错误暴露出来。编辑/etc/rc.local,把第一行改成:

#!/bin/sh

然后重启服务并查看详细日志:

sudo systemctl restart rc-local.service sudo journalctl -u rc-local.service -n 20 --no-pager

日志里会清晰显示哪一行报错(比如command not foundPermission denied)。

6.2 脚本执行了,但生成的文件不在预期位置

这是因为rc.local是在 root 用户上下文中运行的,它的“当前工作目录”是/root,而不是你编辑脚本时所在的目录。

解决方法

  • 所有路径务必写绝对路径(如/opt/mystartup/test.sh,而不是./test.sh);
  • 在 shell 脚本开头强制cd到目标目录(如cd /opt/mystartup);
  • Python 脚本中写文件时,也用绝对路径(如/opt/mystartup/sb.txt)。

6.3 中文字符导致脚本崩溃

如果你的 Python 脚本里写了中文(比如f.write("你好")),而系统 locale 没设置好,就会报UnicodeEncodeError

解决方法(二选一)

  • 方案 A(推荐):避免在开机脚本中使用中文,用英文或 ASCII 字符替代;
  • 方案 B:在test.sh中显式设置语言环境:
#!/bin/bash export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 cd /opt/mystartup python3 ce.py exit 0

7. 总结:你已经掌握了一个可靠的系统级自动化入口

到这里,你已经完成了整个流程:理解了 systemd 下rc.local失效的原因,亲手创建了服务单元,初始化了启动脚本,挂载了业务逻辑,并掌握了排错的核心方法。这不是一个“一次性的技巧”,而是一个可复用的工程能力——今后任何需要开机自启的任务,无论是备份脚本、监控程序、数据库初始化,还是 Web 服务预热,你都可以用同样的模式接入。

回顾一下关键动作:

  • rc-local.service是 systemd 的“翻译官”,把老式脚本变成现代服务;
  • /etc/rc.local是你的“总控台”,所有启动命令都从这里出发;
  • chmod +xexit 0是两个看似微小、实则致命的细节;
  • 绝对路径、显式cdpython3替代python,是避免环境差异的黄金习惯。

最后提醒一句:虽然rc.local很方便,但对于长期运行的服务(比如 Web 服务器),更推荐为它单独编写 systemd service 文件。rc.local最适合做“一次性初始化”或“轻量级调度入口”。它的价值,不在于替代专业方案,而在于给你一个简单、稳定、随时可用的起点。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 5:44:02

AI绘画新选择:Qwen-Image Web服务快速入门指南

AI绘画新选择:Qwen-Image Web服务快速入门指南 Qwen-Image-2512-SDNQ-uint4-svd-r32 Web服务让AI绘图真正“开箱即用”,无需配置环境、不写代码、不调参数,打开浏览器就能生成高质量图片。本文将带你从零开始,10分钟完成部署、理解…

作者头像 李华
网站建设 2026/4/18 5:41:32

Xinference实战:在笔记本上运行多模态AI模型的完整流程

Xinference实战:在笔记本上运行多模态AI模型的完整流程 你是否想过,在一台普通的笔记本电脑上,不依赖云服务、不配置复杂环境,就能直接运行支持图文理解、语音处理、文本生成的多模态AI模型?不是调用API,而…

作者头像 李华
网站建设 2026/4/21 10:41:17

StructBERT中文语义系统应用:银行信贷申请材料语义完整性校验

StructBERT中文语义系统应用:银行信贷申请材料语义完整性校验 1. 为什么银行信贷审核需要语义完整性校验 你有没有遇到过这样的情况:客户提交的信贷申请材料里,写着“本人月收入5万元”,但附件里的工资流水却只有8000元&#xf…

作者头像 李华
网站建设 2026/4/18 10:06:59

GLM-4.7-Flash效果展示:30B MoE在C-Eval与CMMLU榜单实测表现

GLM-4.7-Flash效果展示:30B MoE在C-Eval与CMMLU榜单实测表现 1. 为什么这款模型值得你多看两眼? 你可能已经见过不少标榜“最强中文大模型”的名字,但真正能在专业评测中稳居前列、同时又跑得快、开箱即用的,其实没几个。GLM-4.…

作者头像 李华
网站建设 2026/4/21 8:29:09

浏览器里就能用!Fun-ASR跨平台使用体验

浏览器里就能用!Fun-ASR跨平台使用体验 你有没有过这样的经历:会议刚结束,录音文件还在手机里躺着,而老板已经催着要纪要;培训视频拍了一堆,却没人有时间逐字整理;客服通话成百上千条&#xff…

作者头像 李华
网站建设 2026/4/18 12:52:52

告别漫长等待:Z-Image-Turbo实现4步极速出图体验

告别漫长等待:Z-Image-Turbo实现4步极速出图体验 你有没有过这样的经历:在AI绘图工具里输入一段精心打磨的提示词,点击“生成”,然后盯着进度条数秒、十秒、甚至更久——心里默念“快一点、再快一点”,结果画面刚浮现…

作者头像 李华