备份脚本中date命令必须用单引号包裹格式串(如date '+%y%m%d\_%h%m'),否则cron下因sh解析和%符号问题易失效;rsync排除需注意路径匹配逻辑;重定向须用> log 2>&1顺序;mysql备份要显式指定socket或用配置文件避免密码泄露。

备份脚本里 date 命令加不加引号,结果天差地别
不加引号的 date +%Y%m%d_%H%M 在 cron 里常变成空字符串或报错,因为 cron 默认用 sh 解析,不支持 bash 的花括号扩展,且未引号包裹时,% 符号可能被 shell 提前解释或截断。
- 务必用单引号包裹整个格式串:
date '+%Y%m%d_%H%M'(双引号也行,但单引号更安全,避免变量误展开) - 别在脚本里直接写
$(date +%Y%m%d)—— cron 环境里$()可能不可用,优先用反引号或确保 SHELL=/bin/bash 显式指定 - 测试方法:在 cron 同一用户下手动执行
env -i SHELL=/bin/sh /bin/sh -c 'date +%Y%m%d',看是否报错
rsync 备份时忽略临时文件,--exclude 路径写法很关键
写成 --exclude '.git' 只能忽略当前目录下的 .git,而 --exclude '/.git' 或 --exclude '*/.git' 才能覆盖子目录——cron 脚本通常从根路径触发,路径匹配逻辑容易误判。
- 推荐统一用
--exclude='*.tmp'、--exclude='.DS_Store'这类无斜杠的模式,简单可靠 - 要排除绝对路径下的缓存目录(如
/var/cache/apt),得配合--exclude-from或用--filter,单个--exclude对绝对路径无效 - 注意 rsync 的
-a默认包含-r和-l,但不会自动跳过挂载点;加--one-file-system防止意外备份到其他磁盘
cron 日志没输出?2>&1 和重定向顺序不能错
cron 不捕获 stdout/stderr,脚本静默失败是常态。只写 > /var/log/backup.log 会丢掉错误,而 > /var/log/backup.log 2>&1 才把 stderr 合并进日志——顺序颠倒(比如 2>&1 > log)会导致 stderr 仍输出到邮件或丢弃。
- 实操建议:所有 cron 条目末尾都加上
>> /var/log/backup.log 2>&1(用>>追加,避免日志被覆盖) - 如果用
MAILTO=your@email.com,错误仍会发邮件,但内容可能被截断;优先依赖本地日志,邮件仅作兜底提醒 - 检查 cron 环境变量:它不加载
~/.bashrc,PATH 往往只有/usr/bin:/bin,rsync或mysqldump若装在/usr/local/bin,必须写绝对路径或在脚本开头 export PATH
MySQL 备份失败常见于权限和 socket 路径不一致
cron 下运行 mysqldump 报 Can't connect to local MySQL server through socket '/tmp/mysql.sock',不是密码错,而是默认 socket 路径和实际不符——mysql --socket 查到的路径,和 cron 环境里 mysqldump 默认找的不一定一样。
- 始终显式指定 socket:
mysqldump --socket=/var/run/mysqld/mysqld.sock -u user -p'pass' db_name - 密码不要裸写在命令行(会被
ps aux看见),改用配置文件:mysqldump --defaults-extra-file=/etc/mysql/backup.cnf db_name,其中backup.cnf权限设为600,内容为[client]\nuser=backup\npassword=xxx - 如果用
systemd管理 MySQL,注意ProtectHome=yes等安全选项可能导致 cron 无法访问 socket,此时应改用 TCP 连接:--host=127.0.0.1 --port=3306
真正麻烦的从来不是写几行备份命令,而是每次系统升级、MySQL 配置变更、或换个发行版后,那些藏在环境变量、socket 路径、shell 兼容性里的细微差异。留好日志,每改一行就手动跑一次,比事后追查三天强得多。









