news 2026/4/16 14:45:45

Linux定时任务与自动化脚本实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux定时任务与自动化脚本实战

前言

服务器运维离不开定时任务:日志清理、数据备份、监控告警、报表生成……手动执行既繁琐又容易遗漏。crontab是Linux下最常用的定时任务工具,配合shell脚本可以实现各种自动化需求。

本文整理crontab的使用技巧和常见自动化脚本,附带踩坑经验。


1. crontab基础

1.1 基本语法

* * * * * command │ │ │ │ │ │ │ │ │ └── 星期(0-7,0和7都是周日) │ │ │ └──── 月份(1-12) │ │ └────── 日期(1-31) │ └──────── 小时(0-23) └────────── 分钟(0-59)

1.2 常用时间表达式

# 每分钟执行* * * * * /path/to/script.sh# 每小时整点执行0* * * * /path/to/script.sh# 每天凌晨2点执行02* * * /path/to/script.sh# 每周一凌晨3点执行03* *1/path/to/script.sh# 每月1号凌晨4点执行041* * /path/to/script.sh# 每5分钟执行*/5 * * * * /path/to/script.sh# 每天8点到18点,每小时执行08-18 * * * /path/to/script.sh# 工作日每天9点执行09* *1-5 /path/to/script.sh# 每天凌晨1点和13点执行01,13* * * /path/to/script.sh

1.3 crontab管理命令

# 编辑当前用户的crontabcrontab-e# 查看当前用户的crontabcrontab-l# 删除当前用户的crontabcrontab-r# 编辑指定用户的crontab(需要root权限)crontab-u username -e# 从文件导入crontabcrontab/path/to/crontab.txt

2. crontab踩坑指南

2.1 环境变量问题

crontab执行环境和交互式shell不同,PATH很精简:

# 错误:直接写命令名* * * * * mysql -e"select 1"# 正确:使用绝对路径* * * * * /usr/bin/mysql -e"select 1"# 或者在脚本开头设置PATH#!/bin/bashexportPATH=/usr/local/bin:/usr/bin:/bin

查看crontab的环境变量

# 创建一个临时任务* * * * *env>/tmp/cron_env.txt

2.2 输出处理

默认情况下,crontab会把输出发到用户邮箱:

# 丢弃所有输出* * * * * /path/to/script.sh>/dev/null2>&1# 只记录错误* * * * * /path/to/script.sh>/dev/null2>>/var/log/cron_error.log# 记录所有输出* * * * * /path/to/script.sh>>/var/log/cron.log2>&1# 记录输出并带时间戳* * * * * /path/to/script.sh2>&1|whilereadline;doecho"$(date):$line";done>>/var/log/cron.log

2.3 特殊字符转义

# 错误:%在crontab中是换行符02* * * /bin/date +%Y%m%d# 正确:转义%02* * * /bin/date +\%Y\%m\%d# 或者放到脚本里执行02* * * /path/to/backup.sh

2.4 执行权限

# 脚本需要可执行权限chmod+x /path/to/script.sh# 或者用bash显式执行* * * * * /bin/bash /path/to/script.sh

2.5 工作目录

# crontab默认工作目录是用户home# 脚本中使用相对路径可能出问题# 解决:在脚本开头切换目录#!/bin/bashcd/path/to/workdir||exit1

3. 实用自动化脚本

3.1 日志清理脚本

#!/bin/bash# clean_logs.sh - 清理过期日志LOG_DIRS=("/var/log/app""/data/logs/nginx""/data/logs/tomcat")KEEP_DAYS=30fordirin"${LOG_DIRS[@]}";doif[-d"$dir"];thenecho"清理目录:$dir"find"$dir"-name"*.log"-mtime +$KEEP_DAYS-deletefind"$dir"-name"*.log.gz"-mtime +$KEEP_DAYS-delete# 清理空目录find"$dir"-type d -empty -delete2>/dev/nullfidone# 清理系统日志journalctl --vacuum-time=${KEEP_DAYS}d2>/dev/nullecho"日志清理完成:$(date)"

crontab配置:

# 每天凌晨3点清理日志03* * * /opt/scripts/clean_logs.sh>>/var/log/clean_logs.log2>&1

3.2 数据库备份脚本

#!/bin/bash# mysql_backup.sh - MySQL备份MYSQL_USER="backup"MYSQL_PASS="your_password"BACKUP_DIR="/data/backup/mysql"KEEP_DAYS=7DATE=$(date+%Y%m%d_%H%M%S)# 创建备份目录mkdir-p"$BACKUP_DIR"# 获取所有数据库databases=$(mysql -u"$MYSQL_USER"-p"$MYSQL_PASS"-e"SHOW DATABASES;"|grep-Ev"(Database|information_schema|performance_schema|sys)")fordbin$databases;doecho"备份数据库:$db"mysqldump -u"$MYSQL_USER"-p"$MYSQL_PASS"\--single-transaction\--routines\--triggers\"$db"|gzip>"$BACKUP_DIR/${db}_${DATE}.sql.gz"done# 清理过期备份find"$BACKUP_DIR"-name"*.sql.gz"-mtime +$KEEP_DAYS-delete# 统计备份大小echo"备份完成,总大小:$(du-sh $BACKUP_DIR|cut-f1)"

3.3 磁盘空间监控脚本

#!/bin/bash# disk_monitor.sh - 磁盘空间监控THRESHOLD=80ALERT_EMAIL="admin@example.com"# 获取磁盘使用率df-h|awk'NR>1 {print $5,$6}'|whilereadusagemount;do# 去掉百分号usage_num=${usage%\%}if["$usage_num"-gt"$THRESHOLD"];thenmessage="警告:$mount磁盘使用率$usage超过阈值${THRESHOLD}%"echo"$message"# 发送告警(可选)# echo "$message" | mail -s "磁盘告警 - $(hostname)" $ALERT_EMAIL# 或者发送到钉钉/企业微信# curl -X POST "https://webhook.url" -d "{\"text\":\"$message\"}"fidone

3.4 服务健康检查脚本

#!/bin/bash# service_check.sh - 服务健康检查SERVICES=("nginx:80""mysql:3306""redis:6379""app:8080")check_port(){localname=$1localport=$2ifnc-z localhost$port2>/dev/null;thenecho"[OK]$name(port$port)"return0elseecho"[FAIL]$name(port$port)"return1fi}forservicein"${SERVICES[@]}";doname=${service%:*}port=${service#*:}if!check_port"$name""$port";then# 尝试重启服务echo"尝试重启$name..."systemctl restart$name2>/dev/nullsleep5if!check_port"$name""$port";thenecho"重启失败,发送告警"# 发送告警逻辑fifidone

3.5 SSL证书到期检查

#!/bin/bash# ssl_check.sh - SSL证书到期检查DOMAINS=("www.example.com""api.example.com")WARN_DAYS=30fordomainin"${DOMAINS[@]}";do# 获取证书到期时间expiry_date=$(echo|openssl s_client -servername"$domain"-connect"$domain:443"2>/dev/null|\openssl x509 -noout -enddate2>/dev/null|cut-d=-f2)if[-z"$expiry_date"];thenecho"[ERROR] 无法获取$domain证书信息"continuefi# 计算剩余天数expiry_epoch=$(date-d"$expiry_date"+%s)current_epoch=$(date+%s)days_left=$(((expiry_epoch-current_epoch)/86400))if[$days_left-lt$WARN_DAYS];thenecho"[WARN]$domain证书将在$days_left天后过期"elseecho"[OK]$domain证书剩余$days_left天"fidone

4. 多服务器定时任务管理

4.1 问题场景

当管理多台服务器时,定时任务分散在各机器上,维护起来很麻烦:

  • 修改任务要逐台登录
  • 不知道哪台机器上有什么任务
  • 任务执行情况难以统计

4.2 集中管理方案

方案一:Ansible管理crontab

# crontab.yml-hosts:alltasks:-name:部署日志清理任务cron:name:"clean logs"minute:"0"hour:"3"job:"/opt/scripts/clean_logs.sh >> /var/log/clean_logs.log 2>&1"-name:部署磁盘监控任务cron:name:"disk monitor"minute:"*/10"job:"/opt/scripts/disk_monitor.sh"

执行:

ansible-playbook -i inventory crontab.yml

方案二:集中式任务调度

使用专门的任务调度系统:

  • XXL-JOB
  • Airflow
  • Jenkins Pipeline

这些系统可以集中管理所有服务器的定时任务,还有执行日志、失败重试、依赖调度等功能。

4.3 跨网络批量管理

如果服务器分布在不同网络环境(办公室、家里、云服务器),Ansible连接就比较麻烦。

常见解决方案:

  1. 跳板机:所有机器都能连接的中转服务器
  2. VPN:把所有机器组到一个网络
  3. 组网工具:WireGuard、ZeroTier、星空组网等,配置简单,把机器串成虚拟局域网

用组网工具的好处是配置一次后,后续直接用内网IP管理,不用关心机器实际在哪个网络。Ansible的inventory直接写虚拟IP就行:

# inventory [web] 10.10.0.1 10.10.0.2 [db] 10.10.0.10

5. 任务执行监控

5.1 记录任务执行日志

#!/bin/bash# 通用任务包装器# usage: task_wrapper.sh <task_name> <command>TASK_NAME=$1shiftCOMMAND="$@"LOG_DIR="/var/log/cron_tasks"LOG_FILE="$LOG_DIR/${TASK_NAME}.log"mkdir-p"$LOG_DIR"START_TIME=$(date'+%Y-%m-%d %H:%M:%S')echo"[$START_TIME] 开始执行:$TASK_NAME">>"$LOG_FILE"# 执行任务OUTPUT=$($COMMAND2>&1)EXIT_CODE=$?END_TIME=$(date'+%Y-%m-%d %H:%M:%S')DURATION=$SECONDSecho"$OUTPUT">>"$LOG_FILE"echo"[$END_TIME] 执行完成,退出码:$EXIT_CODE,耗时:${DURATION}秒">>"$LOG_FILE"echo"---">>"$LOG_FILE"# 如果失败,发送告警if[$EXIT_CODE-ne0];thenecho"任务失败:$TASK_NAME, 退出码:$EXIT_CODE"# 告警逻辑fiexit$EXIT_CODE

使用方式:

# crontab02* * * /opt/scripts/task_wrapper.sh mysql_backup /opt/scripts/mysql_backup.sh

5.2 任务执行统计

#!/bin/bash# task_stats.sh - 统计任务执行情况LOG_DIR="/var/log/cron_tasks"echo"=== 任务执行统计 ==="echo""forlogin"$LOG_DIR"/*.log;dotask_name=$(basename"$log".log)# 统计成功/失败次数total=$(grep-c"执行完成""$log"2>/dev/null||echo0)success=$(grep"退出码: 0""$log"|wc-l)failed=$((total-success))# 最后执行时间last_run=$(grep"开始执行""$log"|tail-1|grep-oP'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}')printf"%-20s 总计: %-5s 成功: %-5s 失败: %-5s 最后执行: %s\n"\"$task_name""$total""$success""$failed""$last_run"done

6. 高级技巧

6.1 防止任务重复执行

#!/bin/bash# 使用flock防止重复执行LOCK_FILE="/tmp/my_task.lock"exec200>"$LOCK_FILE"flock -n200||{echo"任务正在执行中,退出"exit1}# 正常的任务逻辑echo"开始执行..."sleep60echo"执行完成"

或者在crontab中直接使用:

* * * * * flock -n /tmp/my_task.lock /path/to/script.sh

6.2 任务超时控制

# 使用timeout命令限制执行时间* * * * *timeout300/path/to/script.sh# 超时后发送SIGKILL* * * * *timeout-k10300/path/to/script.sh

6.3 随机延迟启动

避免所有机器同时执行任务(比如同时访问某个API):

#!/bin/bash# 随机延迟0-300秒sleep$((RANDOM%300))# 执行实际任务/path/to/actual_script.sh

6.4 任务依赖

#!/bin/bash# 先执行备份,成功后再清理/opt/scripts/mysql_backup.sh&&/opt/scripts/clean_old_backup.sh

更复杂的依赖关系建议用专门的调度系统。


7. systemd timer替代方案

systemd timer是crontab的现代替代:

# /etc/systemd/system/backup.service [Unit] Description=MySQL Backup [Service] Type=oneshot ExecStart=/opt/scripts/mysql_backup.sh
# /etc/systemd/system/backup.timer [Unit] Description=Run backup daily [Timer] OnCalendar=*-*-* 02:00:00 Persistent=true [Install] WantedBy=timers.target

启用:

systemctlenablebackup.timer systemctl start backup.timer# 查看所有timersystemctl list-timers

systemd timer优点

  • 日志集成到journalctl
  • 支持更复杂的时间表达式
  • 可以设置资源限制
  • 错过的任务可以补执行(Persistent=true)

总结

场景crontab表达式
每分钟* * * * *
每5分钟*/5 * * * *
每小时0 * * * *
每天凌晨2点0 2 * * *
每周一9点0 9 * * 1
每月1号0 0 1 * *
工作日0 9 * * 1-5

最佳实践

  1. 使用绝对路径:脚本和命令都用绝对路径
  2. 处理输出:重定向到日志文件,避免邮件堆积
  3. 防止重复:使用flock防止任务重叠
  4. 超时控制:长任务加timeout限制
  5. 监控告警:记录执行日志,失败时告警
  6. 集中管理:多服务器用Ansible或调度系统统一管理
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 16:36:59

Java之构造方法

什么是构造方法&#xff1f;构造方法是 Java 中一种特殊的方法&#xff0c;它的核心作用是&#xff1a;在创建对象&#xff08;使用new关键字&#xff09;时&#xff0c;初始化该对象的成员变量构造方法解决什么问题&#xff1f;构造方法解决给对象初始化的问题构造方法怎么使用…

作者头像 李华
网站建设 2026/4/16 12:34:49

想 2026 转行网络安全?前景、工作内容及薪资水平一次说透

如果你计划在2026年转行到网络安全领域&#xff0c;以下是一些建议&#xff0c;可以帮助你顺利过渡并打下坚实的基础 1、薪资情况 初级职位&#xff08;0-3年经验&#xff09; 薪资范围&#xff1a;大约 8k-15k/月&#xff08;根据地区、公司规模和工作内容有所不同&#xff…

作者头像 李华
网站建设 2026/4/16 14:19:16

【干货】2026年AI大模型趋势预测:AI智能体将如何改变编程开发?附ChatGPT+DeepSeek学习资料,小白程序员必看!

AI大模型领地 报告&#xff1a;**2026年中国AI智能体营销趋势与发展报告蓝皮书&#xff08;191页&#xff09; AI 智能体作为具备自主感知、决策与执行能力的 “数字业务伙伴”&#xff0c;正重塑商业格局与营销范式。2026 年&#xff0c;AI 智能体已从被动工具升级为主动参与者…

作者头像 李华
网站建设 2026/4/15 10:21:16

【Java毕设源码分享】基于springboot+vue的产品订单管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华