5分钟搞定开机启动脚本,Linux新手也能轻松上手
你是不是也遇到过这样的问题:写好了一个监控脚本、一个数据同步程序,或者一个自动备份工具,每次重启服务器后都要手动运行一次?看着终端里重复敲命令的自己,心里默默叹气——这哪是自动化,这是“人工自动化”啊。
别急,今天这篇教程就是为你准备的。不需要懂 systemd 的底层原理,不用背一堆参数,更不用翻几十页文档。只要5分钟,你就能让自己的脚本在系统一开机就安静、可靠、准时地跑起来。全程用大白话讲解,每一步都配了可直接复制粘贴的命令,连刚装完 Ubuntu 的新手也能照着做成功。
我们不讲抽象概念,只讲“你现在最需要知道的那几件事”。下面开始。
1. 先确认你的系统用的是什么(30秒搞定)
不是所有 Linux 都一样。就像手机有安卓和 iOS,Linux 启动管理也有“老派”和“新派”。你得先知道自己的系统属于哪一类,才能选对方法。
打开终端,输入这一行:
ps -p 1 -o comm=按回车后,如果看到输出是systemd,恭喜你,你用的是现代主流系统(Ubuntu 16.04+、CentOS 7+、Debian 10+、Fedora 等),接下来的方法专为你设计。
如果看到的是init,说明你用的是非常老的系统(比如 CentOS 6 或更早),但这种情况现在极少见。本文默认你看到的是systemd——这也是99%的新手实际面对的情况。
小提醒:别担心记不住命令。这条只是帮你确认环境,确认完就不用再管它了。我们马上进入正题。
2. 写一个能开机跑的脚本(1分钟)
脚本本身没玄机,关键就三点:开头写对、路径写死、加个日志。
我们来写一个最简单的例子:开机时自动创建一个标记文件,并记录时间。它不干大事,但能100%验证你的整个流程是否走通。
新建一个文件,名字叫my-first-boot.sh:
sudo nano /usr/local/bin/my-first-boot.sh把下面内容完整复制进去(注意:不要漏掉第一行#!/bin/bash):
#!/bin/bash # 这是我的第一个开机脚本 LOG_FILE="/var/log/my-first-boot.log" echo "$(date): 开机脚本已启动,正在执行..." >> "$LOG_FILE" touch /tmp/boot_success_flag echo "$(date): 标记文件创建完成!" >> "$LOG_FILE" exit 0保存并退出(nano 编辑器里按Ctrl+O→ 回车 →Ctrl+X)。
然后给它加上“能被执行”的权限:
sudo chmod +x /usr/local/bin/my-first-boot.sh做完这步,你的脚本就准备好了。它会:
- 在
/tmp/下生成一个叫boot_success_flag的空文件; - 把执行时间记到
/var/log/my-first-boot.log里; - 所有路径都是绝对路径,不怕环境变量缺失。
为什么必须用绝对路径?
因为开机时系统还没加载你平时用的那些环境(比如.bashrc),ls、python3这些命令找不到。所以脚本里所有命令和文件路径,都得写全,比如/bin/touch而不是touch。我们上面用了touch是因为/bin在默认 PATH 里,但保险起见,你以后写复杂脚本时,建议统一写成/bin/touch。
3. 创建 systemd 服务配置(2分钟,抄就行)
现在,我们要告诉系统:“这个脚本,开机时请帮我跑一次。”
systemd 不认脚本,它只认一种叫 “service 文件” 的配置。我们来建一个,名字就叫my-first-boot.service。
sudo nano /etc/systemd/system/my-first-boot.service粘贴以下内容(一字不差):
[Unit] Description=我的第一个开机脚本 After=multi-user.target [Service] Type=oneshot ExecStart=/usr/local/bin/my-first-boot.sh User=root RemainAfterExit=yes [Install] WantedBy=multi-user.target逐行解释一下,让你心里有底:
[Unit]里的After=multi-user.target表示:等系统基本服务(网络、磁盘、用户管理等)都准备好之后再运行,避免抢跑。[Service]里的Type=oneshot是关键——它告诉 systemd:“这个脚本跑完就结束,不用一直占着”,非常适合一次性任务(比如初始化、备份、创建文件)。ExecStart=后面填的就是你刚才写的脚本的绝对路径。User=root表示用管理员身份运行(因为我们要写日志到/var/log/,普通用户没权限)。RemainAfterExit=yes是个贴心设置:它让 systemd 认为“服务一直处于激活状态”,即使脚本已经执行完了。这样你查状态时不会看到“inactive”,而是“active (exited)”,更直观。
小技巧:如果你的脚本想以普通用户身份运行(比如启动你自己的 Python 程序),把
User=root改成User=yourusername就行,比如User=alice。安全第一,能不用 root 就不用。
4. 启用并测试(1分钟,立竿见影)
配置写完,systemd 还不知道有这回事。我们需要两步操作,让它“读取新配置”并“设为开机启动”。
# 第一步:让 systemd 重新扫描所有配置文件 sudo systemctl daemon-reload # 第二步:启用开机自启(注意:不是 start!) sudo systemctl enable my-first-boot.service现在,我们来手动触发一次,看看它能不能立刻跑起来(相当于模拟开机):
sudo systemctl start my-first-boot.service检查结果是否符合预期:
# 查看服务状态(应该显示 active (exited)) sudo systemctl status my-first-boot.service # 查看日志内容(你应该能看到两条时间记录) sudo tail -n 3 /var/log/my-first-boot.log # 检查标记文件是否存在 ls -l /tmp/boot_success_flag如果三者都返回了你期待的结果(状态是 active、日志有时间、文件存在),恭喜你——你已经成功了!整个过程不到5分钟,而且你亲手验证了每一步。
为什么先
enable再start?enable是“登记备案”,告诉系统“下次开机请记得我”;start是“现在就干一次”。两者不冲突,可以同时存在。很多新手卡在这一步,以为enable就等于“现在运行”,其实不是。
5. 常见问题与快速修复(30秒应急包)
刚上手时,最容易遇到三个问题。我把它们列出来,配上一句命令就能解决,不用百度、不用重装:
❌ 问题1:执行systemctl status显示failed,日志里说“Permission denied”
→原因:脚本没加执行权限。
→命令修复:
sudo chmod +x /usr/local/bin/my-first-boot.sh sudo systemctl daemon-reload sudo systemctl restart my-first-boot.service❌ 问题2:systemctl start没报错,但/tmp/boot_success_flag文件没出现
→原因:脚本里用了相对路径,或者ExecStart写错了路径。
→命令修复(快速定位):
# 手动运行脚本,看报什么错 sudo /usr/local/bin/my-first-boot.sh # 如果报错,就根据提示改脚本;如果没报错但文件还是没生成,检查脚本里 touch 命令的路径❌ 问题3:journalctl里看不到日志,或日志为空
→原因:脚本输出没被 systemd 捕获(比如你用了>>重定向到文件,但文件路径错了)。
→命令修复(最简单方案):
删掉脚本里所有>>和2>&1,让输出直接交给 systemd 管理:
把脚本里的这两行:
echo "$(date): ..." >> "$LOG_FILE" touch /tmp/boot_success_flag改成:
echo "$(date): 开机脚本已启动,正在执行..." touch /tmp/boot_success_flag echo "$(date): 标记文件创建完成!"然后重载并重启:
sudo systemctl daemon-reload sudo systemctl restart my-first-boot.service sudo journalctl -u my-first-boot.service -n 10 --no-pager记住这个原则:新手阶段,优先让脚本输出直接进 systemd 日志(
journalctl),比自己管日志文件更省心。等你熟悉了,再按需加日志重定向。
6. 进阶小贴士:让脚本更靠谱(可选,但强烈建议)
你现在已掌握核心技能。下面这几个小技巧,能让你的脚本从“能跑”升级为“稳跑”,特别适合真实项目:
6.1 加个失败重试(脚本网络请求时很管用)
如果你的脚本要访问网络(比如下载配置、调用 API),可能第一次失败。加两行,让它失败后自动再试一次:
在 service 文件的[Service]区块下,加上:
Restart=on-failure RestartSec=5意思是:如果脚本退出码不是 0(即失败了),就等5秒后重试一次。
6.2 指定工作目录(避免“找不到文件”尴尬)
很多脚本依赖同目录下的配置文件或数据。在[Service]区块里加一行:
WorkingDirectory=/opt/myapp/这样脚本执行时,当前目录就是/opt/myapp/,./config.json就能正常读取。
6.3 给脚本传参数(一条命令,多种用途)
比如你想让同一个脚本既能做备份,又能做清理。修改 service 文件:
ExecStart=/usr/local/bin/my-script.sh backup # 或 ExecStart=/usr/local/bin/my-script.sh cleanup然后在脚本里用$1接收参数:
case "$1" in backup) echo "执行备份..." ;; cleanup) echo "执行清理..." ;; esac一句话总结进阶逻辑:
systemd的强大,不在于它多复杂,而在于它把“什么时候跑”“谁来跑”“跑坏了怎么办”这些运维常识,变成了几行清晰的配置。你不用发明轮子,只要学会拧紧几颗螺丝。
7. 总结:你已经掌握了 Linux 自动化的第一把钥匙
回顾一下,这5分钟你做了什么:
- 确认了系统类型,避开了90%的兼容性陷阱;
- 写了一个带日志、用绝对路径的健壮脚本;
- 创建了一个
Type=oneshot的 systemd 服务配置; - 用
enable+start两步完成了注册与验证; - 学会了用
status和journalctl快速排错。
这不是终点,而是起点。你现在可以:
- 把监控脚本设为开机启动;
- 让数据库自动初始化;
- 让 Web 服务随系统一起醒来;
- 甚至写个脚本,开机时自动发邮件告诉你“服务器已上线”。
所有这些,用的都是今天这同一套方法。没有魔法,只有清晰的步骤和可验证的结果。
别再让“每次重启都要手动跑一遍”拖慢你的效率。从今天开始,让 Linux 真正为你工作。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。