news 2026/2/19 20:51:51

测试脚本让rc.local回归,Ubuntu老用户福音

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
测试脚本让rc.local回归,Ubuntu老用户福音

测试脚本让rc.local回归,Ubuntu老用户福音

你是不是也怀念那个简单直接的/etc/rc.local?一行命令写进去,重启就生效——不用记 systemd 的复杂语法,不用折腾服务单元文件,更不用区分 user 和 system 作用域。对很多从 Ubuntu 16.04 甚至更早版本一路用过来的老用户来说,rc.local不仅是启动机制,更是一种习惯、一种确定性。

但自 Ubuntu 18.04 起,rc.local默认被禁用:它还在系统里,却像被悄悄抽走了电源——文件存在,服务不启,脚本不跑。不少人在systemd.service文件里反复调试WantedBy=、纠结Type=、排查journalctl -u rc-local的报错,最后发现:其实只要三步,就能让rc.local完全回归,原样可用。

本文不讲理论、不堆概念,只做一件事:用一个可验证的测试脚本,带你亲手恢复rc.local启动能力,并确保它在 Ubuntu 20.04/22.04 上稳定运行。全程命令可复制、步骤可回溯、效果可验证——就像当年你第一次在/etc/rc.local里写下echo "Hello" > /tmp/startup.log那样踏实。


1. 为什么需要“恢复”rc.local?真相很简单

很多人误以为 Ubuntu “删除了”rc.local,其实完全相反:它被完整保留,只是默认未启用,且 systemd 对其支持做了最小化封装。

关键事实有三点:

  • /etc/rc.local文件本身始终存在(空文件或带注释模板),但默认无执行权限
  • 系统自带rc-local.service单元,位于/lib/systemd/system/rc-local.service,但缺少[Install]段,无法被enable
  • systemd 要求rc.local必须以#!/bin/bash开头、具备+x权限,且必须在multi-user.target阶段之后运行——而默认配置没满足这些

换句话说:不是不能用,是“没配好”。而配好的成本,远低于学透 systemd 的全部规则。

验证当前状态:运行以下命令,你会看到典型的老用户困境

systemctl status rc-local # 输出通常为:Unit rc-local.service could not be found. ls /lib/systemd/system/rc-local* # 通常只显示:/lib/systemd/system/rc-local.service(存在但不可用)

2. 三步实操:让rc.local真正“活过来”

我们不修改任何核心 systemd 配置,不覆盖系统文件,只做必要补全。所有操作均基于标准 Ubuntu 20.04/22.04(桌面版或服务器版),无需额外安装包。

2.1 补全rc-local.service:加一段就能启用

rc-local.service缺少[Install]段,导致systemctl enable失败。我们只需追加两行:

sudo sed -i '/\[Service\]/a [Install]\nWantedBy=multi-user.target\nAlias=rc-local.service' /lib/systemd/system/rc-local.service

这条命令的作用是:在[Service]段后插入标准的[Install]配置,明确声明该服务应在multi-user.target(即常规多用户运行级别)启用,并设置别名rc-local.service便于调用。

验证是否成功:

grep -A2 "\[Install\]" /lib/systemd/system/rc-local.service # 应输出: # [Install] # WantedBy=multi-user.target # Alias=rc-local.service

2.2 创建并配置/etc/rc.local:写你的第一行启动命令

Ubuntu 默认的/etc/rc.local是空的或仅含注释。我们创建一个带标准头、可执行、含测试逻辑的版本:

sudo tee /etc/rc.local << 'EOF' #!/bin/bash # rc.local test script for Ubuntu 20.04/22.04 # This file is executed at the end of each multiuser runlevel. # Ensure exit code is 0 (required by systemd) exit 0 # === Your startup commands go BELOW this line === # Example: log boot time and hostname echo "[$(date)] Booted on $(hostname)" >> /var/log/rc-local.log echo "RC_LOCAL_TEST_SUCCESS" >> /tmp/rc-local-test.flag EOF

注意关键点:

  • 第一行#!/bin/bash不可省略,否则 systemd 拒绝执行
  • exit 0必须放在实际命令之前(这是 systemd 的硬性要求:rc.local 必须以成功退出码结束)
  • 所有真实命令写在exit 0之后,它们仍会被执行
  • 我们写入/var/log/rc-local.log/tmp/rc-local-test.flag作为可验证的痕迹

赋予执行权限:

sudo chmod +x /etc/rc.local

2.3 启用并验证:一次重启,全程可测

现在,让 systemd 认识这个服务:

# 重新加载 systemd 配置(使修改生效) sudo systemctl daemon-reload # 启用 rc-local 服务(开机自动启动) sudo systemctl enable rc-local # 立即启动一次(无需重启即可验证) sudo systemctl start rc-local

验证是否成功运行:

# 查看服务状态(应显示 active (exited)) sudo systemctl status rc-local # 检查日志文件是否生成 ls -l /var/log/rc-local.log /tmp/rc-local-test.flag # 查看内容 cat /var/log/rc-local.log # 输出类似:[Wed 10 Apr 2024 15:23:41 CST] Booted on ubuntu-server

如果以上全部通过,恭喜——rc.local已完全回归。接下来,我们用一个更贴近真实需求的测试脚本,彻底验证它的可靠性。


3. 进阶测试:模拟真实场景的开机启动任务

光写日志还不够。我们来模拟一个典型需求:开机自动启动一个 Python 脚本,监听本地端口并记录启动时间。这比单纯 echo 更能暴露环境问题(如 PATH、用户上下文、依赖缺失等)。

3.1 编写测试脚本:simple-server.py

在用户主目录下创建一个极简 HTTP 服务脚本,仅用于验证启动流程:

mkdir -p ~/startup-test cat > ~/startup-test/simple-server.py << 'EOF' #!/usr/bin/env python3 import http.server import socketserver import datetime import os # 记录启动时间到文件 with open("/tmp/simple-server-started.txt", "w") as f: f.write(f"Started at {datetime.datetime.now()}\n") f.write(f"PID: {os.getpid()}\n") # 启动一个占位 HTTP 服务(不阻塞主线程) class Handler(http.server.SimpleHTTPRequestHandler): def do_GET(self): self.send_response(200) self.end_headers() self.wfile.write(b"Simple server is running (test only)") # 注意:此服务仅用于验证启动,不长期运行 if __name__ == "__main__": with socketserver.TCPServer(("", 8000), Handler) as httpd: # 仅监听1秒,然后退出(避免阻塞 rc.local) httpd.timeout = 1 httpd.handle_request() EOF

赋予执行权限:

chmod +x ~/startup-test/simple-server.py

3.2 将其集成到rc.local

编辑/etc/rc.local,在exit 0之前添加调用(注意:必须在exit 0之前,否则不会执行):

sudo sed -i '/exit 0/i \# Start simple test server\nsu $USER -c "python3 /home/$USER/startup-test/simple-server.py > /tmp/simple-server.log 2>&1 &"' /etc/rc.local

解析这行命令:

  • su $USER -c "...":以当前用户身份运行(避免 root 权限问题)
  • &:后台运行,防止阻塞启动流程
  • > /tmp/simple-server.log 2>&1:捕获所有输出便于调试

3.3 最终验证:重启后检查一切是否就绪

sudo reboot

重启后,立即检查:

# 1. rc.local 日志是否更新 tail -n 3 /var/log/rc-local.log # 2. 测试标志文件是否存在 ls -l /tmp/rc-local-test.flag /tmp/simple-server-started.txt # 3. 检查进程是否启动过(即使已退出,log 中应有记录) cat /tmp/simple-server.log 2>/dev/null | head -n 5 # 4. 确认 rc-local 服务状态正常 systemctl is-active rc-local # 应输出:active

如果/tmp/simple-server-started.txt存在且含时间戳,/tmp/simple-server.log有输出,rc-local状态为 active——说明你的rc.local不仅回来了,而且能可靠执行任意用户级脚本。


4. 常见问题与避坑指南(来自真实踩坑经验)

即使按上述步骤操作,部分用户仍会遇到问题。以下是高频场景及一招解决法:

4.1 问题:重启后卡在紫色启动界面,无法进入桌面

原因rc.local中的命令未后台运行(缺少&),或执行时间过长阻塞multi-user.target
解决

  • 确保所有长时命令末尾加&
  • /etc/rc.local开头添加超时保护:
    # 在 #!/bin/bash 下方添加 timeout 30s /bin/bash -c 'while ! systemctl is-system-running --wait; do sleep 1; done'

4.2 问题:脚本中命令找不到(如python3: command not found

原因rc.local由 root 执行,PATH 环境变量极简(通常只有/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin)。
解决

  • 使用绝对路径调用命令(如/usr/bin/python3
  • 或在脚本开头显式设置 PATH:
    export PATH="/usr/local/bin:/usr/bin:/bin"

4.3 问题:systemctl enable rc-local报错 “Failed to enable unit: Unit file rc-local.service does not exist”

原因rc-local.service文件被意外删除,或路径错误(注意是rc-local.service,不是rc.local.service)。
解决

# 恢复原始服务文件(Ubuntu 22.04 示例) sudo cp /usr/lib/systemd/system/rc-local.service /lib/systemd/system/ # 然后重做 2.1 步骤

4.4 问题:/etc/rc.local修改后不生效,systemctl status rc-local显示 failed

快速诊断

# 查看详细错误 sudo journalctl -u rc-local -n 50 --no-pager # 最常见错误:/etc/rc.local 无执行权限,或缺少 #!/bin/bash ls -l /etc/rc.local head -n 1 /etc/rc.local

5. 为什么坚持用rc.local?三个不可替代的理由

有人会问:既然有 systemd,为何还要“复古”?答案很务实:

  • 零学习成本:老用户无需重学systemctl --userWantedBy=Type=forking等概念,一行命令即生效
  • 调试极其简单:直接sudo /etc/rc.local手动执行,错误立刻可见;而 systemd 服务需journalctl排查,路径、权限、环境变量层层嵌套
  • 兼容性无敌:同一份/etc/rc.local脚本,在 Ubuntu、Debian、CentOS、Raspberry Pi OS 上几乎无需修改——而 systemd 服务文件在不同发行版间常需调整WantedBy=ExecStartPre=

这不是拒绝进步,而是尊重工程效率。当你需要快速验证一个想法、部署一个临时服务、或维护一台生产边缘设备时,rc.local提供的是确定性,而非抽象性。


6. 总结:你已掌握Ubuntu最可靠的启动方式

回顾整个过程,你只做了三件小事:

  1. rc-local.service补上[Install]段,让它能被enable
  2. 创建一个带标准头、可执行、含测试逻辑的/etc/rc.local
  3. 用一个真实 Python 脚本验证它能在用户上下文中稳定运行

没有深奥理论,没有冗余配置,没有“可能有效”的模糊步骤。每一步都有明确命令、即时反馈、可验证结果。

从此,你可以在/etc/rc.local里自由添加:

  • docker-compose up -d启动容器栈
  • ~/my-app/start.sh &后台运行自研服务
  • curl -s https://api.example.com/health | logger上报健康状态
  • 任何你想在开机时自动执行的命令

它不再是一个被遗忘的遗物,而是你 Ubuntu 系统中最值得信赖的启动入口。

--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/7 17:22:20

YimMenu安全使用与功能拓展实战指南

YimMenu安全使用与功能拓展实战指南 【免费下载链接】YimMenu YimMenu, a GTA V menu protecting against a wide ranges of the public crashes and improving the overall experience. 项目地址: https://gitcode.com/GitHub_Trending/yi/YimMenu 一、基础认知&#x…

作者头像 李华
网站建设 2026/2/12 19:13:35

不用再查资料了!开机启动脚本一篇讲清楚

不用再查资料了&#xff01;开机启动脚本一篇讲清楚 你是不是也经历过这样的场景&#xff1a;写好了一个监控脚本、一个数据采集程序&#xff0c;或者一个Web服务&#xff0c;每次重启服务器都要手动运行一遍&#xff1f;反复输入bash /path/to/script.sh&#xff0c;还要确认…

作者头像 李华
网站建设 2026/2/15 22:12:14

茅台预约自动助手:智能神器让你告别每日手动抢购烦恼

茅台预约自动助手&#xff1a;智能神器让你告别每日手动抢购烦恼 【免费下载链接】campus-imaotai i茅台app自动预约&#xff0c;每日自动预约&#xff0c;支持docker一键部署 项目地址: https://gitcode.com/GitHub_Trending/ca/campus-imaotai 还在为每天定闹钟抢茅台…

作者头像 李华
网站建设 2026/2/19 2:52:39

告别二指禅:QWERTY Learner科学打字训练系统全解析

告别二指禅&#xff1a;QWERTY Learner科学打字训练系统全解析 【免费下载链接】qwerty-learner 为键盘工作者设计的单词记忆与英语肌肉记忆锻炼软件 / Words learning and English muscle memory training software designed for keyboard workers 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/2/16 16:10:10

YOLOv10镜像训练教程:零基础实现自定义检测

YOLOv10镜像训练教程&#xff1a;零基础实现自定义检测 你是否曾为训练一个能识别自家产线零件的目标检测模型而卡在环境配置上&#xff1f;是否试过反复重装CUDA、PyTorch、Ultralytics&#xff0c;却总在ImportError: libcudnn.so not found或torch version mismatch中耗尽耐…

作者头像 李华
网站建设 2026/2/19 15:04:49

verl容器化部署:Docker镜像使用实战

verl容器化部署&#xff1a;Docker镜像使用实战 1. verl 是什么&#xff1f;为什么需要容器化部署 verl 不是一个普通工具&#xff0c;而是一套专为大型语言模型&#xff08;LLMs&#xff09;后训练打造的强化学习&#xff08;RL&#xff09;训练框架。它不是实验室里的概念验…

作者头像 李华