技术演进中的开发沉思-128 shell编程篇:定时脚本 - 实践
在运维工作里,有两类需求特别常见:一是 “到点让脚本自动跑”,比如每天凌晨 2 点备份数据、每周日清理日志;二是 “系统一启动,脚本就跟着跑”,比如服务器开机后自动启动监控程序。这就像给脚本装了 “闹钟” 和 “开机自启开关”,不用人手动触发,脚本就能按计划干活。我还记得早年团队里有个实习生,每天手动到点跑备份脚本,有次加班忘了,导致数据没备份,差点出大事 —— 后来用上了定时和启动运行的技巧,这类 “人为失误” 就再也没发生过。如今梳理这部分内容,才发现这看似简单的 “自动化”,其实是运维效率提升的关键一步。

定时与启动运行
1. 定时执行
手动触发脚本就像 “靠人记时间做事”,总有忘的时候;而定时执行则是给脚本装了 “智能闹钟”,到点就提醒脚本干活,分 “单次定时” 和 “循环定时” 两种,满足不同场景需求。
(1)at 命令
如果只需要让脚本 “跑一次”,比如 “今天晚上 8 点执行数据同步脚本”,用at命令就够了,它像个 “临时闹钟”,响一次就失效。用法很简单,先输入at 20:00 today(指定今天 20 点执行),按回车后会进入at的编辑模式,再输入要执行的命令(比如./sync_data.sh),最后按Ctrl+D结束编辑 —— 系统会提示 “job 1 at Fri Sep 29 20:00:00 2025”,表示 1 号定时任务已创建,到点就会自动执行。
要是想指定更精确的时间,比如 “明天下午 3 点 15 分”,可以写at 15:15 tomorrow;想 “10 分钟后” 执行,就写at now + 10 minutes,时间语法很灵活。当年有次需要紧急同步一次跨机房数据,又不想熬夜等,就用at now + 2 hours设了 2 小时后执行,到点脚本自动跑完,省了不少事。
不过at命令有个特点:它执行的任务默认会把输出发到用户邮箱(比如/var/mail/root),如果想指定输出文件,就在命令后加重定向,比如at 20:00 today后输入./sync_data.sh > sync.log 2>&1,这样输出就会存到sync.log里,不用去邮箱找。
(2)cron 定时
如果需要脚本 “重复跑”,比如每天、每周固定时间执行,at命令就不够用了,这时候cron就是 “常驻闹钟”,能按周期循环触发任务,是运维里最常用的定时工具。
cron的核心是crontab(定时任务列表),用crontab -e就能编辑自己的定时任务(普通用户只能编辑自己的,root 能编辑所有用户的)。任务格式是 “分 时 日 月 周 命令”,五个时间字段分别对应 “分钟(0-59)、小时(0-23)、日期(1-31)、月份(1-12)、星期(0-6,0 是周日)”,用空格分隔,最后跟要执行的命令。
比如 “每天凌晨 2 点执行备份脚本”,就写:
0 2 * * * /home/user/backup.sh > /home/user/backup.log 2>&1这里的*表示 “所有值”,0 2 * * *就是 “每天(日、月、周都是所有值)的 2 点 0 分”。我当年给服务器配置每日备份时,就用了这个定时任务,每天早上看backup.log,就能知道备份有没有成功,特别省心。
再比如 “每周日晚上 10 点清理日志”,就写:
0 22 * * 0 /home/user/clean_log.sh22是 22 点,0是周日,意思是 “每周日 22 点 0 分执行清理脚本”。如果想 “每小时的第 30 分钟执行一次监控检查”,就写30 * * * * /home/user/monitor.sh,30表示 “每小时的 30 分”,其他字段用*,就是 “每小时都执行”。
编辑完保存后,cron会自动生效,不用重启服务(部分系统可能需要systemctl restart crond)。如果想查看已有的定时任务,用crontab -l;想删除所有定时任务,用crontab -r(谨慎使用,会删光所有任务)。当年团队里的日志清理、数据备份、系统检查,全靠cron定时,不用人盯着,效率提升了一大截。
2. 启动时运行
除了 “按点跑”,还有个需求是 “系统一启动,脚本就跑”—— 比如服务器开机后,自动启动监控脚本、自动挂载数据盘脚本。这就像给脚本装了 “开机自启开关”,系统 “起床”,脚本就跟着 “干活”,不用人手动启动。
(1)/etc/rc.local
/etc/rc.local是系统级的启动脚本,系统启动到最后一步时,会执行这个文件里的命令,适合放 “所有用户都需要的启动任务”,比如服务器开机后自动启动 nginx 服务、自动运行全局监控脚本。
用法很简单,用 root 权限编辑/etc/rc.local(比如vim /etc/rc.local),在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.
# 开机自动运行监控脚本
/home/user/monitor.sh > /home/user/monitor_start.log 2>&1
exit 0保存后,要给/etc/rc.local加执行权限(chmod +x /etc/rc.local),不然系统启动时不会执行。当年我给公司的监控服务器配置时,就把监控脚本加到了/etc/rc.local里,不管服务器是重启还是断电后开机,监控脚本都会自动启动,不用运维人员手动操作。
不过要注意:/etc/rc.local里的命令是 “按顺序执行” 的,如果前面的命令卡住,后面的命令就不会执行,所以尽量不要在里面放耗时太久的任务;另外,这里的命令默认用 root 权限执行,要是脚本不需要 root 权限,最好指定用户,比如su - user -c "/home/user/script.sh"(用 user 用户执行脚本)。
(2)~/.bashrc 与~/.bash_profile
如果只想让 “某个用户” 登录时执行脚本(比如用户每次打开终端,自动执行自己的环境变量配置脚本),就用用户主目录下的~/.bashrc或~/.bash_profile,这两个是用户级的启动文件,只对当前用户生效。
~/.bashrc会在 “每次打开终端(非登录 shell)” 时执行,比如在图形界面打开终端、远程连接后打开终端;~/.bash_profile会在 “用户登录时(登录 shell)” 执行,比如远程ssh登录、本地切换用户(su - user)。实际用的时候,很多人会在~/.bash_profile里调用~/.bashrc,保证两种场景都能执行。
比如用户想每次打开终端都自动查看服务器负载,就编辑~/.bashrc(vim ~/.bashrc),在最后加上:
# 每次打开终端显示系统负载
echo "当前系统负载:$(uptime)"保存后,执行source ~/.bashrc让配置立刻生效(不然要等下次打开终端才生效)。下次再打开终端,就会自动显示 “当前系统负载: 21:30:01 up 2 days, 3:15, 2 users, load average: 0.12, 0.08, 0.05”,不用每次手动输uptime。
当年我给团队里的新同事配置开发环境时,就把常用的环境变量、别名(比如alias ll='ls -l')都加到了~/.bashrc里,同事每次打开终端都能直接用,不用重复配置 —— 这就是用户级启动脚本的便利之处,只针对个人需求,不影响其他用户。
最后小结
梳理完定时与启动运行的内容,我想起早年做运维时的一个变化:以前团队里要安排人轮流 “值夜班”,负责凌晨的备份、凌晨的系统检查;后来用上了cron定时,再把关键脚本加到/etc/rc.local里,夜班制度直接取消了,大家不用熬夜,脚本也能按计划跑,出错率还低了 —— 这就是自动化的力量,把人从重复的 “按时干活” 里解放出来,去做更有价值的事。
其实定时与启动运行的核心,是 “用系统规则代替人的记忆”:人会忘事、会疲劳,但系统的定时任务不会,只要配置正确,到点就会执行;人开机后可能会漏启动脚本,但系统的启动文件会按顺序执行,不会漏。这就像工厂里的流水线,一旦设置好流程,机器就会自动运转,不用人盯着每一步。
如今回头看,从脚本控制到定时与启动运行,Shell 脚本的学习路径其实是 “从‘能跑’到‘能控’,再到‘能自动跑’” 的进阶。它或许没有华丽的界面,没有复杂的逻辑,但它能精准解决运维中的 “自动化需求”—— 这也是为什么在云计算、容器化盛行的今天,Shell 脚本依然是运维工程师离不开的工具。而对我们这些老程序员来说,把这些 “解放双手” 的技巧讲清楚,让更多人感受到自动化的便利,也是对技术初心的一种坚守。未完待续...........
 
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号