如何让脚本开机自动运行?测试开机启动脚本来帮你
你有没有遇到过这样的情况:写好了一个监控磁盘空间的脚本,或者一个自动备份日志的小工具,每次重启服务器后都要手动运行一次?既麻烦又容易忘记。其实,Linux系统早就为你准备好了“开机自动运行”的能力——只要配置得当,你的脚本就能在系统启动时安静、可靠地开始工作。
本文不是讲抽象概念,而是聚焦一个具体目标:让你亲手配置一个可验证的开机启动脚本,并用“测试开机启动脚本”这个轻量镜像快速验证效果。整个过程不依赖复杂服务管理器(如systemd的unit文件),而是采用传统但稳定、兼容性极强的SysV init方式,适用于CentOS 6/7(兼容模式)和Ubuntu 16.04及更早版本,也完全能在现代系统中作为学习和调试的可靠路径。
我们不堆砌术语,不绕弯子。每一步都对应一个可观察、可验证的动作,最后你会看到:重启之后,你的脚本真的在后台跑起来了。
1. 明确目标与环境准备
在动手前,先理清三件事:你要启动什么、系统怎么启动、以及如何确认它真的启动了。
1.1 你要启动的是什么?
不是任意一个.sh文件都能直接开机运行。它需要满足两个基本条件:
- 有可执行权限:
chmod +x /path/to/script.sh - 有标准的init脚本结构:包含
start、stop、status等基础动作,以及#!/bin/bash开头的解释器声明
本文使用的镜像名称是“测试开机启动脚本”,它内部已预置了一个符合规范的示例脚本/etc/init.d/mytest.sh。它的作用非常简单:每5秒向/var/log/mytest.log写入一行带时间戳的记录。没有复杂逻辑,只为清晰验证“是否启动”、“是否持续运行”。
1.2 系统怎么启动?理解运行级别(Runlevel)
Linux系统启动时,并非一股脑加载所有服务,而是按“运行级别”(Runlevel)分阶段加载。不同级别代表不同的系统状态,比如单用户模式、多用户文本模式、带图形界面的多用户模式等。
你可以用一条命令立刻知道当前系统默认进入哪个级别:
runlevel输出类似N 5,其中第二个数字5就是当前默认运行级别。这意味着系统启动完成后,会自动加载/etc/rc5.d/目录下的所有启动脚本链接。
关键理解:
/etc/init.d/是所有服务脚本的“源代码仓库”,放在这里的脚本本身不会自动运行;/etc/rcX.d/(X为数字)是“启动任务清单”,里面全是软链接,指向/etc/init.d/中的真实脚本;- 链接名以
S开头表示“Start”(启动),以K开头表示“Kill”(停止);S99test中的99是启动顺序号,数字越大,启动越晚——这很重要,如果你的脚本依赖网络或数据库,就该把它设成S99而不是S01。
1.3 如何确认它真的启动了?
别只信“没报错”。最实在的方法是看日志。我们的测试脚本会持续写入/var/log/mytest.log。只要你在重启后能看到新写入的时间戳,就说明它不仅启动了,而且一直在运行。
你可以随时用这条命令查看最新几行:
tail -n 5 /var/log/mytest.log2. 分步实操:从零配置一个开机启动脚本
现在,我们一步步把/etc/init.d/mytest.sh加入开机启动队列。全程只需5个清晰动作,每个动作都有明确目的和验证方式。
2.1 检查并确保脚本存在且可执行
首先确认镜像中已预置的脚本是否就位:
ls -l /etc/init.d/mytest.sh你应该看到类似这样的输出:
-rwxr-xr-x 1 root root 823 Apr 10 10:20 /etc/init.d/mytest.sh注意最前面的-rwxr-xr-x—— 其中x表示可执行权限。如果没有x,请立即加上:
sudo chmod +x /etc/init.d/mytest.sh小贴士:为什么必须加
x?因为/etc/rcX.d/下的链接只是“指针”,真正执行的是/etc/init.d/里的原始文件。没有执行权限,指针再准也没用。
2.2 确认系统运行级别并进入对应rc目录
再次运行:
runlevel假设输出是N 5,那就进入/etc/rc5.d/:
cd /etc/rc5.d/这个目录里通常已经有很多以S或K开头的链接,比如S10sysklogd、S20ssh。它们都是系统自带服务的启动项。我们要做的,就是在这里加一个属于你自己的。
2.3 创建指向脚本的软链接
这是最关键的一步。我们用ln -s命令创建一个软链接,名字叫S99mytest:
sudo ln -s /etc/init.d/mytest.sh S99mytest注意:
sudo是必须的,因为/etc/rc5.d/是系统目录;/etc/init.d/mytest.sh是绝对路径,不能省略;S99mytest是链接名,S表示启动,99表示最后启动(避免依赖冲突),mytest是你起的名字,清晰易懂。
创建完成后,用ls查看效果:
ls -l S99mytest输出应为:
lrwxrwxrwx 1 root root 24 Apr 10 10:25 S99mytest -> /etc/init.d/mytest.sh箭头->后面的路径正确,就说明链接成功。
2.4 手动测试脚本能否正常启停
在重启前,务必先手动验证脚本本身是否工作正常。这能帮你快速定位是“脚本问题”还是“启动配置问题”。
# 启动脚本 sudo /etc/init.d/mytest.sh start # 查看状态 sudo /etc/init.d/mytest.sh status # 停止脚本 sudo /etc/init.d/mytest.sh stop如果status返回“running”,并且你用tail -f /var/log/mytest.log能看到实时滚动的日志,说明脚本本身完全OK。如果失败,请回头检查脚本内容或权限,不要急于重启。
2.5 重启系统并验证开机生效
一切就绪,现在可以重启了:
sudo reboot等待系统完全重启并重新登录后,立即执行验证:
# 查看脚本状态 sudo /etc/init.d/mytest.sh status # 查看最近5条日志 tail -n 5 /var/log/mytest.log如果状态显示running,且日志时间戳是重启之后的(比如重启发生在10:30,日志里有10:31、10:32的记录),恭喜你,配置成功!
为什么不用等几分钟再看?
因为我们的测试脚本每5秒写一次日志,只要系统启动完成、rc5.d脚本执行完毕,它就会立刻开始工作。你几乎可以在登录后的10秒内得到答案。
3. 常见问题与实用技巧
配置看似简单,但在真实环境中,几个细节常导致“明明配了却没启动”。以下是高频问题和一线工程师的实战建议。
3.1 脚本启动后立刻退出?检查后台运行逻辑
很多新手写的脚本是这样的:
#!/bin/bash echo "Starting mytest..." >> /var/log/mytest.log while true; do echo "$(date): running" >> /var/log/mytest.log sleep 5 done看起来没问题,但SysV init在调用start时,会等待脚本进程返回。而上面这个脚本永远不会返回——它卡在while true里。结果就是init认为“启动失败”,可能直接终止它。
正确做法:让主进程在后台运行,并记录PID。
我们的测试脚本已内置此逻辑:
start() { if [ -f $PIDFILE ]; then echo "$NAME is already running" return 1 fi echo "Starting $NAME..." # 关键:nohup + & + > /dev/null 2>&1 确保后台静默运行 nohup $DAEMON > /dev/null 2>&1 & echo $! > $PIDFILE }nohup防止终端关闭影响进程,&放入后台,$!获取刚启动进程的PID并写入文件——这样start函数才能快速返回,init才认为启动成功。
3.2 Ubuntu 18.04+ 或 CentOS 7+ 怎么办?兼容方案依然有效
你可能会问:“我的系统用的是 systemd,这套 rc.d 还管用吗?”答案是:完全管用,且推荐用于学习和快速验证。
原因有二:
- 大多数现代发行版(包括Ubuntu 18.04+、CentOS 7+)仍完整保留 SysV init 兼容层。
/etc/init.d/脚本会被 systemd 自动转换为 service 单元; - 它比直接写
.service文件更直观、更少出错,特别适合教学和临时调试。
当然,长期生产环境建议迁移到 systemd。但当你只想快速验证“脚本能开机跑吗”,SysV 方式就是最快、最稳的那条路。
3.3 如何禁用或删除这个开机启动?
配置错了?想临时关掉?很简单:
# 方法1:直接删掉软链接(最彻底) sudo rm /etc/rc5.d/S99mytest # 方法2:重命名,加个下划线让它失效(推荐用于临时禁用) sudo mv /etc/rc5.d/S99mytest /etc/rc5.d/_S99mytest然后重启,你会发现日志不再更新,status显示 stopped。想恢复?把名字改回来就行。
4. 进阶思考:不只是“能跑”,还要“跑得好”
配置成功只是第一步。一个真正可靠的开机脚本,还需要考虑这些工程细节:
4.1 启动依赖管理:谁先谁后?
我们的脚本用了S99,意味着它在绝大多数服务之后启动。但如果它需要访问MySQL数据库,而MySQL的启动链接是S20mysql,那S99就刚刚好;但如果它依赖某个网络服务,而该服务是S99network,那S99就可能抢在它前面,导致启动失败。
解决方案:查看/etc/init.d/中其他脚本的# Required-Start:注释行。这是SysV的标准依赖声明。你可以给你的脚本加上:
# Required-Start: $local_fs $network $syslog mysql然后运行sudo update-rc.d mytest defaults(Debian/Ubuntu)或sudo chkconfig --add mytest(CentOS),系统会自动计算最优启动序号。
4.2 日志轮转:别让日志撑爆磁盘
测试脚本每5秒写一行,一天就是17280行。长期运行必须做日志切割。
Linux 提供了logrotate工具。只需新建/etc/logrotate.d/mytest:
/var/log/mytest.log { daily missingok rotate 7 compress delaycompress notifempty create 644 root root }这样,每天凌晨自动归档旧日志,最多保留7天,压缩节省空间。
4.3 错误捕获与告警:让问题主动找你
一个健壮的脚本不该默默失败。可以在start()函数末尾加一句:
if ! ps -p $(cat $PIDFILE) > /dev/null; then echo "$(date): FAILED to start $NAME" >> /var/log/mytest.log # 这里可以加邮件通知、写入系统日志等 fi让失败留下痕迹,而不是消失在黑夜里。
5. 总结
你现在已经掌握了让任意脚本在Linux系统开机时自动运行的核心方法。这不是魔法,而是一套清晰、可验证、跨版本兼容的机制。
回顾一下关键步骤:
- 确保脚本有
x权限,并具备标准的start/stop/status接口; - 用
runlevel确认系统启动级别,进入对应的/etc/rcX.d/目录; - 用
ln -s创建SxxYourScriptName软链接,序号决定启动时机; - 重启前务必手动
start和status测试; - 重启后通过日志和状态命令双重验证。
更重要的是,你学会了如何排查:是脚本本身的问题?是权限问题?是启动顺序问题?还是日志没刷新?每一个“为什么没启动”,现在都有了明确的排查路径。
下一步,你可以把任何重复性运维任务——比如清理临时文件、同步配置、检查端口健康——封装成这样的脚本,让系统替你值守。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。