├── README.md └── backup.sh /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry-backup 2 | 树莓派备份脚本 3 | 4 | 优点:备份后的镜像在恢复时会自动扩容空间 5 | 6 | 运行`sudo bash backup.sh`将在当前路径生成备份文件 7 | 8 | 生成的镜像名为`raspi-backup.img` 9 | 10 | 一键备份: 11 | ``` 12 | curl -sSL https://raw.githubusercontent.com/mghcool/Raspberry-backup/master/backup.sh | sudo bash 13 | ``` 14 | -------------------------------------------------------------------------------- /backup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e #当命令以非零状态退出时,则退出shell 4 | 5 | Color_End="\033[0m" 6 | Color_Red="\033[31m" 7 | Color_Green="\033[32m" 8 | 9 | if [ `id -un` != "root" ];then 10 | echo -e "$Color_Red权限不足,退出脚本! $Color_End" 11 | exit 1 12 | fi 13 | 14 | #安装必要的软件安装包 15 | echo -e "$Color_Green安装必要的软件...$Color_End" 16 | apt-get install -qq -y dosfstools dump parted kpartx rsync 17 | apt-get clean 18 | 19 | # 设置文件存放目录 20 | BACKUP_DIR=`pwd` 21 | BACK_UP_DIR=$BACKUP_DIR/raspi-backup 22 | FILE=$BACK_UP_DIR/raspi-backup.img #备份后的img文件名 23 | mkdir $BACK_UP_DIR 24 | 25 | #创建镜像img文件 26 | echo -e "$Color_Green创建img文件...$Color_End" 27 | ROOT=`df -P | grep /dev/root | awk '{print $3}'` #获取 ROOT的文件大小 28 | MMCBLK0P1=`df -P | grep /dev/mmcblk0p1 | awk '{print $2}'` #获取主目录的文件大小 29 | ALL=`echo $ROOT $MMCBLK0P1 | awk '{print int(($1+$2)*1.2)}'` #生成一个比原文件大1.2倍的IMG文件 30 | echo "预计生成文件大小:$(($ALL/1024))MB" 31 | echo "root 大小是 $(($ROOT/1024))MB" 32 | echo "boot 大小是 $(($MMCBLK0P1/1024))MB" 33 | echo "文件路径是 $FILE" 34 | dd if=/dev/zero of=$FILE bs=1K count=$ALL status=progress 35 | 36 | #格式化分区 37 | echo -e "$Color_Green格式化root和boot...$Color_End" 38 | P1_START=`fdisk -l /dev/mmcblk0 | grep /dev/mmcblk0p1 | awk '{print $2}'` 39 | P1_END=`fdisk -l /dev/mmcblk0 | grep /dev/mmcblk0p1 | awk '{print $3}'` 40 | P2_START=`fdisk -l /dev/mmcblk0 | grep /dev/mmcblk0p2 | awk '{print $2}'` 41 | echo "boot扇区: $P1_START - $P1_END " 42 | echo "root扇区: :$P2_START - end" 43 | parted $FILE --script -- mklabel msdos 44 | parted $FILE --script -- mkpart primary fat32 ${P1_START}s ${P1_END}s 45 | parted $FILE --script -- mkpart primary ext4 ${P2_START}s -1 46 | parted $FILE --script -- quit 47 | 48 | # mount 49 | echo -e "$Color_Green挂载分区...$Color_End" 50 | loopdevice_dst=`losetup -f --show $FILE` 51 | echo "loop分区在 $loopdevice_dst" 52 | PART_BOOT="/dev/dm-0" 53 | PART_ROOT="/dev/dm-1" 54 | sleep 1 55 | device_dst=`kpartx -va $loopdevice_dst | sed -E 's/.*(loop[0-9])p.*/\1/g' | head -1` 56 | sleep 1 57 | device_dst="/dev/mapper/${device_dst}" 58 | sleep 1 59 | mkfs.vfat ${device_dst}p1 -n boot 60 | sleep 1 61 | mkfs.ext4 ${device_dst}p2 -L rootfs 62 | sleep 1 63 | 64 | # 复制文件到img 65 | echo -e "$Color_Green复制文件到img...$Color_End" 66 | echo "备份分区 /dev/boot" 67 | dst_boot_path=$BACK_UP_DIR/dst_boot 68 | mkdir $dst_boot_path 69 | mount -t vfat ${device_dst}p1 $dst_boot_path 70 | cp -rfp /boot/* $dst_boot_path 71 | echo "备份boot完成" 72 | echo "备份分区 /dev/root" 73 | dst_root_path=$BACK_UP_DIR/dst_root 74 | mkdir $dst_root_path 75 | sleep 1 76 | mount -t ext4 ${device_dst}p2 $dst_root_path 77 | cd $dst_root_path 78 | chmod 777 $dst_root_path/ 79 | #通过rsync复制根目录文件到IMG镜像中,排除了一些不需要同步的文件 80 | rsync -ax \ 81 | --info=progress2 \ 82 | --no-inc-recursive \ 83 | --exclude="$FILE" \ 84 | --exclude=$BACK_UP_DIR \ 85 | --exclude=$BACKUP_DIR/$0 \ 86 | --exclude=/sys/* \ 87 | --exclude=/proc/* \ 88 | --exclude=/tmp/* / $dst_root_path/ 89 | echo "备份root完成" 90 | 91 | # 设置自动扩展空间 92 | echo -e "$Color_Green设置自动扩展空间 ...$Color_End" 93 | sed -i 's/exit 0/sudo bash \/expand-rootfs.sh \&/' $dst_root_path/etc/rc.local 94 | echo "exit 0" >> $dst_root_path/etc/rc.local 95 | cat > $dst_root_path/expand-rootfs.sh << EOF 96 | #!/bin/bash 97 | 98 | sed -i '/sudo bash \/expand-rootfs.sh &/d' /etc/rc.local 99 | rm "\`pwd\`/\$0" 100 | echo -e "\033[33m两秒后扩展分区空间!\033[0m" 101 | sleep 2 102 | raspi-config --expand-rootfs 103 | echo -e "\033[33my一秒后重启系统!\033[0m" 104 | sleep 1 105 | reboot 106 | EOF 107 | 108 | 109 | #返回目录 $BACKUP_DIR 110 | cd $BACKUP_DIR 111 | sync 112 | 113 | #替换PARTUUID 这步非常重要,liunx启动时会对PARTUUID有特定的指定,备份的时候是把旧的也同步过来,需要根据新的IMG文件来更新PARTUUID 114 | echo -e "$Color_Green替换PARTUUID ...$Color_End" 115 | opartuuidb=`blkid -o export /dev/mmcblk0p1 | grep PARTUUID` 116 | opartuuidr=`blkid -o export /dev/mmcblk0p2| grep PARTUUID` 117 | npartuuidb=`blkid -o export ${device_dst}p1 | grep PARTUUID` 118 | npartuuidr=`blkid -o export ${device_dst}p2 | grep PARTUUID` 119 | echo "BOOT uuid $opartuuidb 替换为 $npartuuidb" 120 | echo "ROOT uuid $opartuuidr 替换为 $npartuuidr" 121 | sed -i "s/$opartuuidr/$npartuuidr/g" $dst_boot_path/cmdline.txt 122 | sed -i "s/$opartuuidb/$npartuuidb/g" $dst_root_path/etc/fstab 123 | sed -i "s/$opartuuidr/$npartuuidr/g" $dst_root_path/etc/fstab 124 | 125 | #清理释放装载的文件夹 126 | echo -e "$Color_Green清理释放装载的文件夹...$Color_End" 127 | echo "dst_boot_path: $dst_boot_path" 128 | echo "dst_root_path : $dst_root_path" 129 | echo "device_dst: ${device_dst}" 130 | echo "loopdevice_dst: $loopdevice_dst " 131 | umount $dst_boot_path 132 | umount $dst_root_path 133 | kpartx -d ${device_dst}p1 134 | kpartx -d ${device_dst}p2 135 | kpartx -d $loopdevice_dst 136 | losetup -d $loopdevice_dst 137 | rm -rf $dst_boot_path 138 | rm -rf $dst_root_path 139 | chmod 766 $FILE 140 | mv $FILE $BACKUP_DIR 141 | rm -rf $BACK_UP_DIR 142 | 143 | echo -e "$Color_Green备份完成。$Color_End" 144 | exit 0 145 | --------------------------------------------------------------------------------