news 2026/4/3 4:29:06

再也不用手动跑脚本,这个设置太实用了

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
再也不用手动跑脚本,这个设置太实用了

再也不用手动跑脚本,这个设置太实用了

你是不是也经历过这样的场景:写好了一个数据采集脚本、一个日志清理工具,或者一个定时监控程序,每次重启服务器后都得手动登录、cd到目录、再敲一遍python monitor.py?重复操作不仅费时,还容易遗漏——尤其在多台设备上部署时,光是检查是否启动就让人头疼。

其实,Linux系统早就有成熟的机制来解决这个问题。只是很多人卡在“不知道从哪下手”或者“试了几次没成功就放弃了”。今天这篇内容,不讲抽象原理,不堆参数配置,就用最直白的方式,带你把“开机自动运行脚本”这件事真正落地。整个过程只需要6步,每一步都有明确指令、常见坑点提醒和验证方法,哪怕你刚接触Linux命令行,也能照着做完、立刻见效。

我们用的是Ubuntu 18.04及后续版本(如20.04、22.04)通用的systemd方案,它比老版本的rc.local更稳定、更可控,也更容易排查问题。重点来了:这不是教你怎么“凑合用”,而是帮你搭一条真正可靠、可维护、能长期运行的自动化通道。


1. 为什么老办法不管用了?

在Ubuntu 14.04时代,大家习惯直接编辑/etc/rc.local文件,在里面加一行python /path/to/script.py,保存后重启就能生效。但到了Ubuntu 18.04,这个文件默认不再被系统读取——不是删了,而是“被禁用了”。

原因很简单:Ubuntu切换到了systemd作为初始化系统,而rc.local只是一个兼容性遗留接口,需要显式启用才能工作。很多教程只说“改一下rc.local就行”,却没告诉你:光改文件内容没用,必须先让系统认识它、信任它、愿意执行它。

这就像给快递员留了一张纸条说“请把包裹放门口”,但如果没告诉他你是谁、门锁密码是多少、甚至没给他开门的权限,那张纸条就只是废纸。

所以,我们的第一步,不是写脚本,而是给系统发一张“通行证”


2. 创建systemd服务单元:让rc.local重新被识别

systemd通过“服务单元文件”来管理各类启动任务。我们要做的,就是为rc.local创建一个专属的服务定义,告诉systemd:“这个文件是可信的,允许它在多用户模式下运行。”

2.1 新建rc-local.service文件

打开终端,执行以下命令:

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

小提示:如果你不熟悉vim,可以用sudo nano /etc/systemd/system/rc-local.service替代,nano更直观,按Ctrl+O保存,Ctrl+X退出。

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

这段配置的意思是:

  • 这个服务叫rc-local,作用是兼容旧版rc.local;
  • 只有当/etc/rc.local这个文件真实存在时,才尝试启动;
  • 启动方式是“forking”(后台进程模式),适合shell脚本;
  • 不设超时限制(TimeoutSec=0),避免脚本稍慢就被系统杀掉;
  • RemainAfterExit=yes表示:即使脚本执行完了,也认为服务仍在运行——这对rc.local这种“一次性执行”的场景很关键;
  • 最后一句说明:它应该在系统进入标准多用户状态(即我们日常使用的图形或命令行环境)时被拉起。

2.3 验证文件是否创建成功

执行以下命令查看文件是否存在且内容正确:

ls -l /etc/systemd/system/rc-local.service

你应该看到类似输出:

-rw-r--r-- 1 root root 327 Jun 15 10:20 /etc/systemd/system/rc-local.service

如果文件大小接近320字节,说明内容基本完整。下一步,我们来准备那个核心载体——rc.local本身。


3. 编写并配置rc.local:你的启动总控台

rc.local在这里不直接写业务逻辑,而是作为一个“启动索引”——就像电脑桌面的快捷方式,它不干活,但它知道该让谁干活、怎么干。

3.1 创建rc.local文件

sudo vim /etc/rc.local

3.2 填入标准模板(含关键细节)

粘贴以下内容(特别注意第一行#!/bin/sh -e和最后一行exit 0,缺一不可):

#!/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 "看到这行字,说明rc.local已成功加载。" > /usr/local/test.log exit 0

关键细节说明:

  • #!/bin/sh -e:指定解释器为sh,并开启“出错即停”模式(-e)。这意味着只要某一行命令失败(返回非0值),整个脚本就会立即终止,避免错误被掩盖;
  • exit 0:必须有!这是告诉systemd“我执行成功了”。没有它,systemd会认为脚本异常退出,后续步骤可能不触发;
  • echo ... > /usr/local/test.log:这是我们的“心跳检测”。只要这个文件被成功写入,就证明整个链路通了。

3.3 赋予执行权限

sudo chmod +x /etc/rc.local

这一步极其重要。Linux不会执行一个没有“可执行位”的文件,哪怕它语法完全正确。你可以用ls -l /etc/rc.local确认输出中包含x(如-rwxr-xr-x)。


4. 启用并启动服务:让设置真正生效

现在,systemd已经知道rc-local.service的存在,也知道/etc/rc.local是它的执行入口。接下来,我们要正式“激活”它。

4.1 启用服务(开机自启)

sudo systemctl enable rc-local

这条命令的作用是:在系统启动流程中,为rc-local.service创建一个软链接,确保它被纳入启动序列。执行后你会看到类似提示:

Created symlink /etc/systemd/system/multi-user.target.wants/rc-local.service → /etc/systemd/system/rc-local.service.

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

sudo systemctl start rc-local.service

4.3 检查服务状态(必做!)

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 Sat 2024-06-15 10:25:33 CST; 1min 2s ago Docs: man:systemd.special(7) Process: 1234 ExecStart=/etc/rc.local start (code=exited, status=0/SUCCESS)

重点关注三处:

  • enabled:说明已设为开机启动;
  • active (exited):说明服务已成功运行完毕;
  • status=0/SUCCESS:说明脚本执行无报错。

如果看到failedinactive,别急着重来,先看下一条。

4.4 查看日志定位问题(排错利器)

如果状态异常,用这条命令看详细报错:

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

它会显示最近20行该服务的日志。常见错误包括:

  • /etc/rc.local没有执行权限(Permission denied);
  • 脚本里调用了不存在的命令(比如写了python3但系统只有python);
  • 路径写错(比如/home/user/script.py实际是/home/ubuntu/script.py);
  • Python脚本里有中文字符但没声明编码(Python 2尤其敏感)。

5. 把你的脚本真正挂上去:从测试到生产

现在,rc.local已经能稳定运行了。下一步,就是让它去调用你自己的业务脚本。

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

假设你想开机自动运行一个叫data_collector.py的程序,放在/opt/myapp/目录下。

先创建脚本文件:

sudo mkdir -p /opt/myapp sudo vim /opt/myapp/data_collector.py

写一个极简测试版:

# /opt/myapp/data_collector.py with open("/tmp/collector_ran.txt", "w") as f: f.write("采集器已在开机时自动运行!")

5.2 创建一个包装shell脚本(推荐做法)

不建议直接在rc.local里写python /opt/myapp/data_collector.py,因为环境变量、工作目录、Python路径都可能和你手动执行时不一致。更稳妥的方式是写一个中间shell脚本:

sudo vim /opt/myapp/start_collector.sh

内容如下:

#!/bin/bash # 切换到脚本所在目录,避免相对路径出错 cd /opt/myapp # 显式指定python解释器(避免系统默认python版本不符) /usr/bin/python3 /opt/myapp/data_collector.py # 记录执行时间,便于后续排查 echo "$(date): collector started" >> /var/log/collector.log

赋予执行权限:

sudo chmod +x /opt/myapp/start_collector.sh

5.3 修改rc.local,调用你的启动脚本

再次编辑/etc/rc.local

sudo vim /etc/rc.local

exit 0之前,添加这一行:

/opt/myapp/start_collector.sh

完整片段应类似:

#!/bin/sh -e ... echo "看到这行字,说明rc.local已成功加载。" > /usr/local/test.log /opt/myapp/start_collector.sh exit 0

保存退出。现在,每次开机,系统都会自动执行start_collector.sh,进而运行你的Python程序。

5.4 验证效果

重启系统:

sudo reboot

等机器起来后,检查两个关键文件:

# 看rc.local是否执行成功 cat /usr/local/test.log # 看你的业务脚本是否真的运行了 cat /tmp/collector_ran.txt # 看日志是否记录 tail -n 5 /var/log/collector.log

如果三个文件都存在且内容符合预期,恭喜你,自动化通道已经打通。


6. 实用技巧与避坑指南

这套方案看似简单,但在真实环境中,有几个高频问题值得提前了解,帮你省下几小时调试时间。

6.1 环境变量问题:为什么脚本里找不到命令?

你在终端能运行pip list,但rc.local里执行就报command not found?这是因为systemd服务默认不加载用户的shell配置(如.bashrc),PATH路径非常精简。

解决方案:在shell脚本开头显式设置PATH,例如:

#!/bin/bash export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin" cd /opt/myapp python3 data_collector.py

6.2 权限问题:为什么写不了文件?

rc.local是以root身份运行的,但你的脚本可能想往普通用户目录(如/home/ubuntu/logs/)写日志,而root默认没有该用户的写权限。

解决方案:用sudo -u username切换用户执行,例如:

sudo -u ubuntu /opt/myapp/start_collector.sh

6.3 启动时机问题:我的服务依赖网络,但脚本运行时网络还没就绪

rc.local默认在multi-user.target阶段运行,此时网络可能尚未完全配置好(尤其是DHCP获取IP需要时间)。

解决方案:在rc-local.service[Unit]部分增加依赖声明:

[Unit] Description=/etc/rc.local Compatibility ConditionPathExists=/etc/rc.local After=network-online.target Wants=network-online.target

然后重新加载配置:

sudo systemctl daemon-reload sudo systemctl restart rc-local.service

6.4 调试技巧:如何快速验证修改是否生效?

不用每次重启。你可以这样模拟一次完整启动流程:

# 重新加载所有unit文件 sudo systemctl daemon-reload # 重启rc-local服务(相当于重走一遍开机流程) sudo systemctl restart rc-local.service # 立即查看结果 sudo systemctl status rc-local.service

7. 总结:你真正掌握的不只是一个技巧

到这里,你已经完成了一次完整的Linux开机自启实践。回顾一下,你实际构建的是一个可扩展、可维护、可诊断的自动化基础框架

  • 你学会了systemd服务单元的基本写法,以后可以为任何程序(Node.js、Java、Go)创建专属启动服务;
  • 你理解了rc.local的现代定位——它不是过时的古董,而是灵活的启动调度中心;
  • 你掌握了环境隔离、权限控制、依赖管理这些工程化必备意识;
  • 你拥有了快速验证和精准排错的能力,而不是靠“重启试试看”。

更重要的是,这件事的复利价值极高:一旦配置好,它就默默为你工作数月甚至数年,每天节省的几分钟,累积起来就是几天的开发时间。

下次当你又写好一个新脚本,只需三步:放进固定目录、写个启动包装、加一行调用——再也不用手动跑了。


获取更多AI镜像

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

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

[特殊字符]️_开发效率与运行性能的平衡艺术[20260123164212]

作为一名经历过无数项目开发的工程师,我深知开发效率与运行性能之间的平衡是多么重要。在快节奏的互联网行业,我们既需要快速交付功能,又需要保证系统性能。今天我要分享的是如何在开发效率和运行性能之间找到最佳平衡点的实战经验。 &#…

作者头像 李华
网站建设 2026/3/30 11:39:05

通义千问3-14B实战教程:单卡部署+双模式切换详细步骤

通义千问3-14B实战教程:单卡部署双模式切换详细步骤 1. 为什么Qwen3-14B值得你花30分钟部署一次 你有没有遇到过这样的困境:想用大模型处理一份40万字的合同全文,但Qwen2-72B显存爆了,Llama3-70B连加载都卡在半路;想…

作者头像 李华
网站建设 2026/4/3 3:33:06

生成效果差?Live Avatar质量调优实用建议

生成效果差?Live Avatar质量调优实用建议 数字人视频生成正从实验室走向真实业务场景,但不少用户在首次尝试Live Avatar时会遇到一个共性问题:生成的视频模糊、口型不同步、动作僵硬,甚至人物五官变形。这不是模型能力不足&#x…

作者头像 李华
网站建设 2026/4/2 5:55:11

IQuest-Coder-V1免配置部署:云平台镜像快速启动教程

IQuest-Coder-V1免配置部署:云平台镜像快速启动教程 你是不是也遇到过这些情况:想试试最新的代码大模型,结果卡在环境搭建上——CUDA版本对不上、依赖包冲突、显存不够报错、配置文件改来改去还是跑不起来?更别说还要手动下载40B…

作者头像 李华
网站建设 2026/3/27 6:15:27

YOLOv10官版镜像实测:小目标检测效果惊艳又高效

YOLOv10官版镜像实测:小目标检测效果惊艳又高效 1. 为什么这次实测让我眼前一亮 你有没有遇到过这样的场景:监控画面里远处的行人只有指甲盖大小,工业质检中微小的焊点缺陷 barely 可见,无人机航拍图里密集排列的车辆几乎连成一…

作者头像 李华
网站建设 2026/3/28 17:44:41

AutoGLM-Phone推理延迟高?GPU利用率提升50%优化方案

AutoGLM-Phone推理延迟高?GPU利用率提升50%优化方案 1. 为什么AutoGLM-Phone在真机场景下“跑不快” 你有没有试过让AutoGLM-Phone执行一条简单指令,比如“打开微信发条语音给张三”,却等了8秒才开始点击?或者模型明明已加载完成…

作者头像 李华