Linux crontab定时任务不执行常见原因与排查

前言

crontab 写好了却到点不执行,是服务器运维最常见的坑之一。手动跑脚本正常,定时任务却没反应,问题往往不在脚本本身,而在服务状态、环境变量、时间格式和权限。本篇按从易到难的顺序列出排查点。

一、先确认crond服务在运行

systemctl status crond
# 没启动就启动并设开机自启
systemctl start crond
systemctl enable crond

服务没跑,所有定时任务都不会触发,这是第一个要查的。

二、检查定时任务格式是否正确

标准格式:分 时 日 月 周 命令

# 查看当前用户的定时任务
crontab -l
# 例如:每10分钟执行一次脚本
*/10 * * * * /usr/bin/php /www/backup.php

常见格式错误:分钟位置写成了小时、用了 * 却想表示"第1个"、命令路径用了相对路径。

三、查看cron日志,判断有没有触发

# CentOS7 日志位置
tail -f /var/log/cron

到点看日志里有没有出现这条任务:

  • 日志里根本没有:格式没被识别、服务没跑、或时间写错;
  • 日志有执行记录但没效果:是脚本/环境问题,往下查。

四、脚本环境变量问题(高频)

cron 的环境比手动登录干净得多,很多命令找不到、相对路径失败。解决:

  1. 用绝对路径:脚本里和任务里都写全,比如 /usr/bin/php、/www/backup.php;
  2. 开头加载环境:
    */10 * * * * source /etc/profile; /usr/bin/php /www/backup.php
  3. 先手动用cron环境复现:env -i /bin/bash script.sh 模拟干净环境跑一遍。

五、权限与重定向

  • 脚本要有执行权限:chmod +x /www/backup.sh;
  • 脚本没加 shebang(#!/bin/bash)会找不到解释器;
  • 把错误输出留下来方便定位:
    */10 * * * * /usr/bin/php /www/backup.php >> /www/log/cron.log 2>&1

    加了 2>&1,报错就写进日志,不再"静默失败"。

六、其他易漏点

  1. 时区不一致:timedatectl 看系统时区,容器里时间错会导致任务错位;
  2. 日和周同时指定是"或"关系,容易误触发,注意语义;
  3. root和普通用户任务混淆:sudo crontab -l 看root的,普通用户看自己的;
  4. 磁盘满了:日志写不进去,任务看似没执行。

总结

排查顺序:crond服务是否运行 → 任务格式对不对 → /var/log/cron 有没有触发 → 绝对路径和环境变量 → 执行权限与错误重定向 → 时区。手动正常、定时不跑,九成是环境变量和绝对路径问题。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-20 07:26 

MySQL定时备份脚本,自动删除旧备份

前言

数据库数据很重要,必须每天自动备份。写个备份脚本,自动备份+自动删旧的,不用手动管。

一、备份脚本

完整脚本 backup_mysql.sh

#!/bin/bash

# MySQL配置
DB_USER="root"
DB_PASS="your_password"
DB_NAME="mydb"

# 备份目录
BACKUP_DIR="/data/backup/mysql"

# 保留天数
KEEP_DAYS=7

# 日期
DATE=$(date +%Y%m%d_%H%M%S)

# 备份文件名
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"

# 创建目录
mkdir -p $BACKUP_DIR

# 备份并压缩
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_FILE

# 检查备份是否成功
if [ $? -eq 0 ]; then
    echo "[$(date)] 备份成功: $BACKUP_FILE"
else
    echo "[$(date)] 备份失败!"
    exit 1
fi

# 删除7天前的旧备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +$KEEP_DAYS -delete

echo "[$(date)] 旧备份清理完成"

二、脚本说明

各部分解释

部分 说明
DB_USER 数据库用户名
DB_PASS 数据库密码
DB_NAME 要备份的数据库名
BACKUP_DIR 备份存放目录
KEEP_DAYS 保留几天的备份
mysqldump 备份命令
gzip 压缩,节省空间
find -mtime +7 找7天前的文件删除

备份全部数据库

mysqldump -u$DB_USER -p$DB_PASS --all-databases | gzip > $BACKUP_FILE

备份多个数据库

mysqldump -u$DB_USER -p$DB_PASS --databases db1 db2 db3 | gzip > $BACKUP_FILE

三、设置执行权限

chmod +x /data/backup/backup_mysql.sh

四、测试脚本

/data/backup/backup_mysql.sh

看有没有备份文件生成:

ls -lh /data/backup/mysql/

五、设置定时任务

每天凌晨3点备份

crontab -e

添加:

0 3 * * * /data/backup/backup_mysql.sh >> /data/backup/backup.log 2>&1

说明:

  • 0 3 * * * 每天凌晨3点
  • >> backup.log 输出写到日志
  • 2>&1 错误也写进去

查看定时任务

crontab -l

六、备份文件恢复

恢复步骤

# 解压
gunzip < mydb_20261008_030000.sql.gz | mysql -u root -p mydb

或者先解压再恢复

# 解压
gunzip mydb_20261008_030000.sql.gz

# 恢复
mysql -u root -p mydb < mydb_20261008_030000.sql

七、更完善的脚本

带日志和邮件通知的版本

#!/bin/bash

DB_USER="root"
DB_PASS="your_password"
DB_NAME="mydb"
BACKUP_DIR="/data/backup/mysql"
KEEP_DAYS=7
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz"
LOG_FILE="$BACKUP_DIR/backup.log"

mkdir -p $BACKUP_DIR

echo "========== $(date) 开始备份 ==========" >> $LOG_FILE

# 备份
mysqldump -u$DB_USER -p$DB_PASS $DB_NAME 2>>$LOG_FILE | gzip > $BACKUP_FILE

if [ $? -eq 0 ]; then
    FILE_SIZE=$(ls -lh $BACKUP_FILE | awk '{print $5}')
    echo "[$(date)] 备份成功,文件大小: $FILE_SIZE" >> $LOG_FILE
else
    echo "[$(date)] 备份失败!" >> $LOG_FILE
    # 这里可以加邮件通知
    exit 1
fi

# 删除旧备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +$KEEP_DAYS -delete
echo "[$(date)] 清理 $KEEP_DAYS 天前的旧备份完成" >> $LOG_FILE

echo "========== $(date) 备份结束 ==========" >> $LOG_FILE

常见坑

坑1:密码写在脚本里不安全

脚本里明文写了数据库密码。

解决: 用mysql配置文件:

# /root/.my.cnf
[client]
user=root
password=your_password

然后脚本里就不用写密码了:

mysqldump $DB_NAME | gzip > $BACKUP_FILE

设置权限:

chmod 600 /root/.my.cnf

坑2:备份文件太大

不压缩的话备份文件很大。

解决: 用gzip压缩,能压缩到原来的1/10。

坑3:定时任务不执行

cron里写了脚本,但没执行。

原因:

  1. 脚本没加执行权限
  2. 路径写错了
  3. 环境变量不对

解决: 脚本里用全路径,比如 /usr/bin/mysqldump。

坑4:备份完没验证

备份文件损坏了都不知道。

解决: 定期找个测试库恢复一下,看备份能不能用。

坑5:备份文件存在同一台服务器

服务器挂了,备份也没了。

解决: 把备份传到远程服务器或OSS。

# 传到远程服务器
scp $BACKUP_FILE root@192.168.1.20:/data/backup/

总结

备份三步走:

  1. 写备份脚本(mysqldump + gzip + find删旧)
  2. 加执行权限
  3. 加crontab定时任务

记住: 备份不是备份了就完了,要定期验证能不能恢复!

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:59 

MySQL备份数据库,mysqldump定时备份

前言

数据库不备份,出事就完蛋。本文讲用mysqldump备份MySQL,再配crontab定时自动备份。

一、mysqldump基本用法

备份单个数据库

mysqldump -u root -p mydb > /backup/mydb.sql

输入密码后,就把mydb库备份到mydb.sql了。

备份多个数据库

mysqldump -u root -p --databases db1 db2 > /backup/mydbs.sql

备份所有数据库

mysqldump -u root -p --all-databases > /backup/all.sql

备份单个表

mysqldump -u root -p mydb users > /backup/users.sql

二、常用参数

参数 说明
--single-transaction InnoDB一致性备份,不锁表
--routines 备份存储过程和函数
--triggers 备份触发器
--events 备份事件调度器
--master-data=2 记录binlog位置,用于主从
--default-character-set=utf8mb4 指定字符集

推荐完整命令

mysqldump -u root -p \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --default-character-set=utf8mb4 \
  mydb > /backup/mydb_$(date +%Y%m%d).sql

三、压缩备份

备份完太大,直接压缩:

mysqldump -u root -p mydb | gzip > /backup/mydb.sql.gz

恢复的时候:

gunzip < /backup/mydb.sql.gz | mysql -u root -p mydb

四、定时备份脚本

创建备份脚本:

vi /usr/local/bin/mysql_backup.sh

内容:

#!/bin/bash

# 备份目录
BACKUP_DIR=/backup/mysql

# 数据库配置
DB_USER=root
DB_PASS=你的密码
DB_NAME=mydb

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份文件名(带日期)
DATE=$(date +%Y%m%d_%H%M%S)
FILE=$BACKUP_DIR/${DB_NAME}_${DATE}.sql.gz

# 执行备份
mysqldump -u$DB_USER -p$DB_PASS \
  --single-transaction \
  --routines \
  --triggers \
  --default-character-set=utf8mb4 \
  $DB_NAME | gzip > $FILE

# 删除7天前的备份
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete

echo "备份完成:$FILE"

加执行权限:

chmod +x /usr/local/bin/mysql_backup.sh

五、配置crontab定时任务

编辑crontab:

crontab -e

加上:

# 每天凌晨2点备份
0 2 * * * /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

六、恢复备份

恢复普通备份

mysql -u root -p mydb < /backup/mydb.sql

恢复压缩备份

gunzip < /backup/mydb.sql.gz | mysql -u root -p mydb

常见坑

坑1:密码写在命令行里不安全

mysqldump -u root -p123456 mydb > xxx.sql

这样密码会出现在进程列表里。

安全做法: 用配置文件存密码。

# /root/.my.cnf
[mysqldump]
user=root
password=你的密码

权限设600:

chmod 600 /root/.my.cnf

以后备份就不用输密码了:

mysqldump mydb > xxx.sql

坑2:备份时锁表

大库备份的时候,业务卡住了。

原因: 没加 --single-transaction。

解决: InnoDB库一定要加这个参数。

坑3:备份文件是空的

备份完一看,文件0字节。

原因: 密码错了,或者数据库名错了。

解决: 先手动执行一次,看报错。

坑4:备份没包含存储过程

备份后恢复,发现存储过程没了。

原因: mysqldump默认不备份存储过程。

解决: 加 --routines 参数。

总结

三步搞定自动备份:

  1. 写备份脚本
  2. 配crontab定时执行
  3. 定期清理旧备份

记住: 备份了不算数,能恢复才算数。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-8 07:39 

Linux crontab定时任务不执行常见原因与排查

前言

配置好了 crontab 定时任务,时间也写对了,但到点就是不执行?这是很多新手都会遇到的坑。crontab 不执行的原因五花八门,从最基础的语法错误到环境变量问题,再到 SELinux 拦截,排查起来很费时间。本文把常见的 crontab 不执行原因都整理出来,按排查顺序一步步来,基本能解决 90% 的问题。

第一步:确认 crond 服务是否运行

最基础也是最容易忽略的——定时任务服务本身有没有启动。

systemctl status crond

如果显示 inactive (dead),说明服务没启动,先启动它:

systemctl start crond
systemctl enable crond

CentOS7 上定时服务叫 crond,Debian/Ubuntu 上叫 cron,别搞混了。

第二步:检查 crontab 语法是否正确

1. 查看当前用户的定时任务

crontab -l

2. crontab 时间格式

* * * * * 命令
- - - - -
| | | | |
| | | | ----- 星期几 (0 - 7) (0和7都是周日)
| | | ------- 月份 (1 - 12)
| | --------- 日期 (1 - 31)
| ----------- 小时 (0 - 23)
------------- 分钟 (0 - 59)

3. 常见语法错误

错误1:分钟写在最前面

# 错误:每天9点执行(错的)
0 9 * * * /root/backup.sh

# 正确:每天9点执行
0 9 * * * /root/backup.sh

等等,这个其实是对的。真正容易错的是:

错误2:命令路径用了相对路径

# 错误:crontab 里找不到 mysql 命令
0 9 * * * mysql -u root -p123456 dbname < /root/backup.sql

# 正确:用绝对路径
0 9 * * * /usr/bin/mysql -u root -p123456 dbname < /root/backup.sql

crontab 的环境变量和你手动登录时不一样! 它的 PATH 很精简,很多命令找不到。所以要么用绝对路径,要么在脚本里先 source 环境变量。

第三步:检查脚本本身有没有执行权限

很多人写了脚本,但忘了加执行权限:

ls -l /root/backup.sh

如果没有 x 权限,加上:

chmod +x /root/backup.sh

第四步:检查脚本内容有没有问题

1. 脚本里用了相对路径

# 错误:相对路径在 crontab 里会出问题
cd /var/www/html
tar -zcf backup.tar.gz .

# 正确:用绝对路径
cd /var/www/html
tar -zcf /root/backup.tar.gz .

2. 脚本里用了交互式命令

比如 read、ssh 需要交互输入的命令,在 crontab 里是跑不了的,因为没有终端。

3. 脚本开头没写 shebang

# 正确的 shebang
#!/bin/bash

如果脚本没有 shebang,或者 shebang 写错了,执行就会失败。

第五步:检查日志

crontab 的执行日志默认在 /var/log/cron 里:

tail -100 /var/log/cron

如果日志里显示任务被执行了,但结果不对,那就是脚本本身的问题。

如果日志里压根没有这个任务的记录,那就是 crontab 服务本身的问题或者任务格式不对。

第六步:检查环境变量问题

这是最隐蔽的坑。你手动跑脚本没问题,但 crontab 里就是不行,十有八九是环境变量的问题。

排查方法:在脚本开头加上环境变量

#!/bin/bash
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

或者直接在 crontab 里指定:

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
0 9 * * * /root/backup.sh

第七步:检查 SELinux 是不是拦截了

如果 SELinux 开着,可能会拦截 crontab 的操作。查看日志:

tail -100 /var/log/audit/audit.log | grep crontab

如果看到 denied 字样,就是 SELinux 拦截了。

第八步:检查邮箱通知

crontab 默认会把执行结果(包括错误信息)发到执行用户的邮箱里:

mail

或者看 /var/spool/mail/root 文件:

tail -100 /var/spool/mail/root

这里面通常会有具体的错误信息,是排查的好帮手。

常见坑

坑1:环境变量缺失

这是最常见的坑。你手动跑脚本能成,crontab 里就不行,因为 crontab 的环境变量和你登录 shell 的不一样。

解决: 在脚本开头加上 export PATH=...,或者所有命令都用绝对路径。

坑2:脚本没有执行权限

写完脚本忘了 chmod +x,crontab 当然跑不了。

坑3:重定向丢了

crontab 默认会把输出发到邮箱,如果你不想收邮件,可以重定向:

0 9 * * * /root/backup.sh > /dev/null 2>&1

> /dev/null 是丢弃标准输出,2>&1 是把错误输出也重定向到标准输出。

坑4:时间格式写错了

比如把 * * * * * 写成了 * * * *,少了一个字段,直接就不执行。

坑5:用户写错了

你用 root 用户写的 crontab,但实际是别的用户需要跑,当然不执行。用 crontab -u 用户名 -l 查看对应用户的任务。

总结

crontab 不执行的排查顺序:

  1. 先确认 crond 服务启动了没
  2. 检查 crontab 语法格式对不对
  3. 脚本有没有执行权限
  4. 脚本里的命令是不是都用了绝对路径
  5. 看 /var/log/cron 日志有没有执行记录
  6. 看 /var/spool/mail/root 有没有错误信息
  7. 检查 SELinux 是不是拦截了

按这个顺序排查,基本都能找到原因。记住 crontab 的环境变量和你手动登录时不一样,所有命令都用绝对路径,能避免 80% 的问题。

遇到问题加QQ23979811 协助处理


emer 发布于  2026-10-5 07:27 
'); })();