备份脚本独立运行正常,设为cron定时任务时仅能备份/home目录
cron定时备份仅完成首个目录的原因排查与方案优化
仅备份/home目录的核心原因
- shell语法的兼容性差异(根本原因)
你手动执行脚本时运行在交互式Bash环境下,Bash语法规则宽松,哪怕+=与后续拼接内容间存在空格,也能正确识别为字符串拼接逻辑,所有待备份路径都会正常存入变量。但Debian/Ubuntu系统下的cron默认使用dash作为执行shell,dash对变量赋值的语法要求严格:赋值语句必须遵循变量名=值格式,等号两侧不能有空格。你写的每一行路径拼接语句都是inputFiles+= " /var/www"格式,+=与后续字符串之间存在空格,dash会将整行解析为「执行名为inputFiles+=的系统命令」,直接报命令不存在的错误并跳过,导致所有拼接的路径根本没有存入变量——最终传给tar命令的inputFiles变量,只剩下最初赋值的/home,完全匹配你观察到的故障现象。 - 通配符展开的环境缺失
脚本中/etc/ufw/*.*这类带通配符的路径,需要shell环境正确展开才能匹配到实际文件。cron是最小化执行环境,没有加载用户的shell初始化配置,哪怕路径拼接逻辑正常,通配符展开规则也可能和交互shell存在差异,导致带通配符的路径被识别为字面量,找不到匹配文件直接跳过。 - 依赖未初始化的外部环境
手动执行时交互shell会加载完整的环境配置,包括自定义变量、挂载点状态、PATH路径。但cron的执行环境没有这些初始化流程:脚本用到的now变量没有在内部定义,完全依赖外部传入;/mnt/synology挂载点可能因为cron任务触发时间早于系统挂载流程,导致输出路径不存在;脚本里冗余的sudo调用,在root权限的cron环境下可能因为PATH路径不匹配,直接触发执行中断。 - 低级排版截断错误
贴出的脚本中,mysql配置行的注释末尾意外粘贴了下一行samba配置的代码,导致该行语法解析失败,samba路径的追加逻辑完全失效。
备份方案优化建议
- 修复脚本基础语法问题
- 脚本第一行添加明确的解释器声明
#!/bin/bash,强制用Bash执行脚本,规避dash的严格语法兼容性问题 - 去掉冗余的
sudo调用——本身就是root权限执行的cron任务,不需要额外提权 - 路径拼接时去掉
+=与后续内容间的空格,或者直接用标准Bash数组语法维护待备份路径,比如inputFiles+=( "/var/www" "/etc/fstab" "/etc/NetworkManager/NetworkManager.conf" ),打包时用带引号的"${inputFiles[@]}"格式展开数组,避免路径带空格时解析错误 - 脚本内部明确给
now变量赋值,比如写成now=$(date +%Y%m%d_%H%M%S),不要依赖外部环境传入的未定义变量 - 提升脚本健壮性
- 执行tar打包前先做前置检查:确认
/mnt/synology挂载点存在且可写,不存在则先执行挂载命令,挂载失败直接终止脚本并记录错误 - 给所有执行步骤添加日志重定向,把tar的输出、报错都写入专门的日志文件,避免静默失败导致排障无据可依
- 移除不合理的
--exclude=".*"规则:这个规则会将所有点开头的隐藏文件(比如/.ssh下的密钥、/.bashrc这类核心配置)全部排除在备份外,看似是排除临时文件,实际会漏掉大量需要备份的关键内容 - 脚本开头手动定义完整的PATH变量,避免因为cron环境PATH不全找不到tar等命令
- 优化备份存储与恢复逻辑
- 拆分大文件与小配置的备份粒度:把/home、/var/www这类大目录单独打包,/etc下的零散配置文件单独做小体积备份,避免单个压缩包损坏导致全量备份失效
- 每次备份完成后生成压缩包的校验值,定期验证备份文件完整性
- 配置备份留存策略:比如保留最近7天的日备份、每月1日的月度备份留存3个月,避免无限制存储占满NAS磁盘空间
内容的提问来源于stack exchange,提问作者Dr Phil
相关产品推荐
相关产品推荐

