我写了一个简单的 bash 脚本,每天将某些文件备份到备份挂载点并保留最近 3 天的备份。这显然太简单了,因为我偶尔会遇到奇怪的行为,这可以通过在 rm 完成之前执行第一个 mv 来解释。
脚本如下:
#!/bin/bash
mount /mnt/backups
while [ ! -d /mnt/backups/dailyBackup-0 ]
do
echo "Backup mount not present, sleeping..."
sleep 30
done
rm -r /mnt/backups/dailyBackup-2
mv /mnt/backups/dailyBackup-1 /mnt/backups/dailyBackup-2
mv /mnt/backups/dailyBackup-0 /mnt/backups/dailyBackup-1
dirname="/mnt/backups/dailyBackup-0"
mkdir $dirname
cd /
rsync -qr --stats root etc var $dirname
umount /mnt/backups
虽然大多数情况下这没什么问题,但有时我还是会遇到以下情况,看起来 dailyBackup-1 在 dailyBackup-2 删除完成之前就被移动了。如果发生了这种情况,最好的预防方法是什么?
/mnt/backups/dailyBackup-0:
total 0
drwxrwxrwx 1 root root 0 2010-12-07 03:27 var
drwxrwxrwx 1 root root 0 2010-12-07 02:39 root
drwxrwxrwx 1 root root 0 2010-12-07 02:38 etc
/mnt/backups/dailyBackup-1:
total 0
drwxrwxrwx 1 root root 0 2010-12-06 03:26 var
drwxrwxrwx 1 root root 0 2010-12-06 02:32 root
drwxrwxrwx 1 root root 0 2010-12-06 02:32 etc
/mnt/backups/dailyBackup-2:
total 0
drwxrwxrwx 1 root root 0 2010-12-07 02:36 var
drwxrwxrwx 1 root root 0 2010-12-05 03:21 dailyBackup-1
答案1
问题很可能是 rm失败,请注意 var 仍然存在于 dailyBackup-2 中,很可能是因为其中某些文件无法删除。
关于编写系统管理 shell 脚本的一般说明:
a) 一定要检查脚本的(错误)输出,除非你的电子邮件设置有问题,否则你将自动通过 cronjobs 的邮件收到它
b) 始终确保处理可能发生的任何和所有错误(例如,rm 或 mv 失败),最好将 set -e 放在脚本顶部,这样当遇到第一个未处理的错误时,shell 就会退出(为了进行调试,还可以添加 set -x,这样将打印正在执行的所有命令,这样您就可以看到脚本正在做什么)
也回答你原来的问题:rm 在删除所有文件之前永远不会退出,或者更准确地说,在它找到的最后一个文件的 unlink() 系统调用完成之前永远不会退出。(我能想到的唯一一种在取消链接后文件可能仍然存在的情况可能是一些模糊的、有缺陷的网络文件系统……)但 rm 退出并不意味着所有文件都已被成功删除(即使你是 root 并且正在使用 -fr(你甚至没有使用 -f)),例如如果文件在 ext* 文件系统上被标记为不可变,或者如果文件是在 rm 遍历树时新创建的。rm 将通过错误消息和不成功的返回统计信息报告这一点
答案2
尝试改变这个
rm -r /mnt/backups/dailyBackup-2
mv /mnt/backups/dailyBackup-1 /mnt/backups/dailyBackup-2
mv /mnt/backups/dailyBackup-0 /mnt/backups/dailyBackup-1
作为
rm -r /mnt/backups/dailyBackup-2 &&
mv /mnt/backups/dailyBackup-1 /mnt/backups/dailyBackup-2 &&
mv /mnt/backups/dailyBackup-0 /mnt/backups/dailyBackup-1 &&
因此,仅当前一个命令成功完成(或者换句话说,以状态 0 退出)时,才会运行每个命令。
答案3
文件是否位于另一台服务器上,可通过 nfs mount 访问?如果 NFS 设置了软挂载,则无法保证操作能够完成。