把树莓派系统备份到另一个SD卡上(只要一个脚本)

树莓派刻录一个SD卡让你花费了一些时间,而且里面很多配置也花费了不少时间,现在我们插上SD卡读卡器在树莓派系统里运行一个命令就可以把系统备份到SD卡里。

把树莓派系统备份到另一个SD卡上(只要一个脚本)

SSH连接树莓派

首先到树莓派的桌面目录

cd /home/pi/Desktop

新建一个文件

nano rpi_clone.sh

把下面的代码复制然后 保存ctrl+O 退出ctrl+X

<!-- wp:paragraph -->
<p>#!/bin/bash<br>PGM=`basename $0`<br>RSYNC_OPTIONS="--force -rltWDEgopt"<br># List of extra dirs to create under /mnt.OPTIONAL_MNT_DIRS="clone mnt sda sdb rpi0 rpi1"<br># Where to mount the disk filesystems to be rsynced.CLONE=/mnt/clone<br>CLONE_LOG=/var/log/$PGM.log<br>HOSTNAME=`hostname`<br>SRC_BOOT_PARTITION_TYPE=`parted /dev/mmcblk0 -ms p | grep "^1" | cut -f 5 -d:`SRC_ROOT_PARTITION_TYPE=`parted /dev/mmcblk0 -ms p | grep "^2" | cut -f 5 -d:`<br>if [ `id -u` != 0 ]then&nbsp; &nbsp; echo -e "$PGM needs to be run as root.\n"&nbsp; &nbsp; exit 1fi<br>usage()&nbsp; &nbsp; {&nbsp; &nbsp; echo ""&nbsp; &nbsp; echo "usage: $PGM sdN {-f|--force-initialize} {-v|--verbose}"&nbsp; &nbsp; echo " &nbsp; &nbsp;Example: &nbsp;$PGM sda"&nbsp; &nbsp; echo " &nbsp; &nbsp;-v - list all files as they are copied."&nbsp; &nbsp; echo " &nbsp; &nbsp;-f - force initialize the destination partitions"&nbsp; &nbsp; echo ""&nbsp; &nbsp; echo " &nbsp; &nbsp;Clone (rsync) a running Raspberry Pi file system to a destination"&nbsp; &nbsp; echo " &nbsp; &nbsp;SD card 'sdN' plugged into a Pi USB port (via a USB card reader)."&nbsp; &nbsp; echo " &nbsp; &nbsp;$PGM can clone the running system to a new SD card or can"&nbsp; &nbsp; echo " &nbsp; &nbsp;incrementally rsync to existing backup Raspberry Pi SD cards."&nbsp; &nbsp; echo ""&nbsp; &nbsp; echo " &nbsp; &nbsp;If the destination SD card has an existing $SRC_BOOT_PARTITION_TYPE partition 1 and a"&nbsp; &nbsp; echo " &nbsp; &nbsp;$SRC_ROOT_PARTITION_TYPE partition 2, $PGM assumes (unless using the -f option)"&nbsp; &nbsp; echo " &nbsp; &nbsp;that the SD card is an existing backup with the partitions"&nbsp; &nbsp; echo " &nbsp; &nbsp;properly sized and set up for a Raspberry Pi. &nbsp;All that is needed"&nbsp; &nbsp; echo " &nbsp; &nbsp;is to mount the partitions and rsync them to the running system."&nbsp; &nbsp; echo ""&nbsp; &nbsp; echo " &nbsp; &nbsp;If these partitions are not found (or -f), then $PGM will ask"&nbsp; &nbsp; echo " &nbsp; &nbsp;if it is OK to initialize the destination SD card partitions."&nbsp; &nbsp; echo " &nbsp; &nbsp;This is done by a partial 'dd' from the running booted device"&nbsp; &nbsp; echo " &nbsp; &nbsp;/dev/mmcblk0 to the destination SD card /dev/sdN followed by a"&nbsp; &nbsp; echo " &nbsp; &nbsp;fdisk resize and mkfs.ext4 of /dev/sdN partition 2."&nbsp; &nbsp; echo " &nbsp; &nbsp;This creates a completed $SRC_BOOT_PARTITION_TYPE partition 1 containing all boot"&nbsp; &nbsp; echo " &nbsp; &nbsp;files and an empty but properly sized partition 2 rootfs."&nbsp; &nbsp; echo " &nbsp; &nbsp;The SD card &nbsp;partitions are then mounted and rsynced to the"&nbsp; &nbsp; echo " &nbsp; &nbsp;running system."&nbsp; &nbsp; echo ""&nbsp; &nbsp; echo " &nbsp; &nbsp;The SD card destination partitions will be mounted on $CLONE."&nbsp; &nbsp; echo " &nbsp; &nbsp;A log will be written to $CLONE_LOG."&nbsp; &nbsp; echo " &nbsp; &nbsp;Avoid running other disk writing programs when running $PGM."&nbsp; &nbsp; echo ""&nbsp; &nbsp; exit 0&nbsp; &nbsp; }<br>VERBOSE=off<br>while [ "$1" ]do&nbsp; &nbsp; case "$1" in&nbsp; &nbsp; &nbsp; &nbsp; -v|--verbose)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VERBOSE=on&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; RSYNC_OPTIONS=${RSYNC_OPTIONS}v&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ;;&nbsp; &nbsp; &nbsp; &nbsp; -f|--force-initialize)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; FORCE_INITIALIZE=true&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ;;&nbsp; &nbsp; &nbsp; &nbsp; *)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if [ "$DST_DISK" != "" ]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; echo "Bad args"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; usage&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fi&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DST_DISK=$1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ;;&nbsp; &nbsp; esac&nbsp; &nbsp; shiftdone</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>if [ "$DST_DISK" = "" ]then&nbsp; &nbsp; usage&nbsp; &nbsp; exit 0fi<br>if ! cat /proc/partitions | grep -q $DST_DISKthen&nbsp; &nbsp; echo "Destination disk '$DST_DISK' does not exist."&nbsp; &nbsp; echo "Plug the destination SD card into a USB port."&nbsp; &nbsp; echo "If it does not show up &nbsp;as '$DST_DISK', then do a"&nbsp; &nbsp; echo -e "'cat /proc/partitions' to see where it might be.\n"&nbsp; &nbsp; exit 0fi</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>TEST_MOUNTED=`fgrep " $CLONE " /etc/mtab | cut -f 1 -d ' ' `if [ "$TEST_MOUNTED" != "" ]then&nbsp; &nbsp; echo "This script uses $CLONE for mounting filesystems, but"&nbsp; &nbsp; echo "$CLONE is already mounted with $TEST_MOUNTED."&nbsp; &nbsp; echo -e "Unmount $CLONE before running this script.\n"&nbsp; &nbsp; exit 0fi<br>if [ ! -d $CLONE ]then&nbsp; &nbsp; MNT_MOUNT=`fgrep " /mnt " /etc/mtab | cut -f 1 -d ' ' `&nbsp; &nbsp; if [ "$MNT_MOUNT" = "" ]&nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; mkdir $CLONE&nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; echo "$MNT_MOUNT is currently mounted on /mnt."&nbsp; &nbsp; &nbsp; &nbsp; echo -e "Unmount /mnt before running $PGM.\n"&nbsp; &nbsp; &nbsp; &nbsp; exit 0&nbsp; &nbsp; fifi</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p># Borrowed from do_expand_rootfs in raspi-configexpand_rootfs()&nbsp; &nbsp; {&nbsp; &nbsp; # Get the starting offset of the root partition&nbsp; &nbsp; PART_START=$(parted /dev/mmcblk0 -ms unit s p | grep "^2" | cut -f 2 -d:)&nbsp; &nbsp; [ "$PART_START" ] || return 1&nbsp; &nbsp; # Return value will likely be error for fdisk as it fails to reload the&nbsp; &nbsp; # partition table because the root fs is mounted&nbsp; &nbsp; fdisk /dev/$DST_DISK &gt; /dev/null &lt;&lt;EOFpd2np2$PART_START<br>pwqEOF&nbsp; &nbsp; }</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p># =========== Disk Setup and Checks ===========#DST_ROOT_PARTITION=/dev/${DST_DISK}2DST_BOOT_PARTITION=/dev/${DST_DISK}1<br># Check that none of the destination partitions are busy (mounted).#DST_ROOT_CURMOUNT=`fgrep "$DST_ROOT_PARTITION " /etc/mtab | cut -f 2 -d ' ' `DST_BOOT_CURMOUNT=`fgrep "$DST_BOOT_PARTITION " /etc/mtab | cut -f 2 -d ' ' `<br>if [ "$DST_ROOT_CURMOUNT" != "" ] || [ "$DST_BOOT_CURMOUNT" != "" ]then&nbsp; &nbsp; echo "A destination partition is busy (mounted). &nbsp;Mount status:"&nbsp; &nbsp; echo " &nbsp; &nbsp;$DST_ROOT_PARTITION: &nbsp;$DST_ROOT_CURMOUNT"&nbsp; &nbsp; echo " &nbsp; &nbsp;$DST_BOOT_PARTITION: &nbsp;$DST_BOOT_CURMOUNT"&nbsp; &nbsp; echo -e "Aborting!\n"&nbsp; &nbsp; exit 0fi<br># Check that destination partitions are the right type.#DST_BOOT_PARTITION_TYPE=`parted /dev/$DST_DISK -ms p \&nbsp; &nbsp; &nbsp; &nbsp; | grep "^1" | cut -f 5 -d:`DST_ROOT_PARTITION_TYPE=`parted /dev/$DST_DISK -ms p \&nbsp; &nbsp; &nbsp; &nbsp; | grep "^2" | cut -f 5 -d:`</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>if [ "$DST_BOOT_PARTITION_TYPE" != "$SRC_BOOT_PARTITION_TYPE" ] || \&nbsp; &nbsp;[ "$DST_ROOT_PARTITION_TYPE" != "$SRC_ROOT_PARTITION_TYPE" ] || \&nbsp; &nbsp;[ "$FORCE_INITIALIZE" = "true" ]then&nbsp; &nbsp; echo ""&nbsp; &nbsp; if [ "$FORCE_INITIALIZE" = "true" ]&nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; echo "*** Forcing a partition initialization of destination '$DST_DISK' ***"&nbsp; &nbsp; fi<br>&nbsp; &nbsp; echo "The existing partitions on destination disk '$DST_DISK' are:"# &nbsp; fdisk -l /dev/$DST_DISK | grep $DST_DISK&nbsp; &nbsp; parted /dev/$DST_DISK unit MB p \&nbsp; &nbsp; &nbsp; &nbsp; | sed "/^Model/d ; /^Sector/d"&nbsp; &nbsp; if [ "$DST_BOOT_PARTITION_TYPE" != "$SRC_BOOT_PARTITION_TYPE" ]&nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; echo -e " &nbsp;... Cannot find a destination boot file system of type: $SRC_BOOT_PARTITION_TYPE\n"&nbsp; &nbsp; fi&nbsp; &nbsp; if [ "$DST_ROOT_PARTITION_TYPE" != "$SRC_ROOT_PARTITION_TYPE" ]&nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; echo -e " &nbsp;... Cannot find a destination root file system of type: $SRC_ROOT_PARTITION_TYPE\n"&nbsp; &nbsp; fi&nbsp; &nbsp; echo "This script can initialize the destination disk with a partition"&nbsp; &nbsp; echo "structure copied from the currently booted filesytem and then resize"&nbsp; &nbsp; echo "partition 2 (the root filesystem) to use all space on the SD card."&nbsp; &nbsp; echo -n "Do you want to initialize the destination /dev/$DST_DISK? (yes/no): "&nbsp; &nbsp; read resp&nbsp; &nbsp; if [ "$resp" = "y" ] || [ "$resp" = "yes" ]&nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; # Image onto the destination disk a beginning fragment of the&nbsp; &nbsp; &nbsp; &nbsp; # running SD card file structure that spans at least more than&nbsp; &nbsp; &nbsp; &nbsp; # the start of partition 2.&nbsp; &nbsp; &nbsp; &nbsp; #&nbsp; &nbsp; &nbsp; &nbsp; # Calculate the start of partition 2 in MB for the dd.&nbsp; &nbsp; &nbsp; &nbsp; PART2_START=$(parted /dev/mmcblk0 -ms unit MB p | grep "^2" \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | cut -f 2 -d: | sed s/MB// | tr "," "." | cut -f 1 -d.)&nbsp; &nbsp; &nbsp; &nbsp; # and add some slop&nbsp; &nbsp; &nbsp; &nbsp; DD_COUNT=`expr $PART2_START + 8`<br>&nbsp; &nbsp; &nbsp; &nbsp; echo ""&nbsp; &nbsp; &nbsp; &nbsp; echo "Imaging the partition structure, copying $DD_COUNT megabytes..."&nbsp; &nbsp; &nbsp; &nbsp; dd if=/dev/mmcblk0 of=/dev/$DST_DISK bs=1M count=$DD_COUNT<br>&nbsp; &nbsp; &nbsp; &nbsp; # But, though Partion 1 is now imaged, partition 2 is incomplete and&nbsp; &nbsp; &nbsp; &nbsp; # maybe the wrong size for the destination SD card. &nbsp;So fdisk it to&nbsp; &nbsp; &nbsp; &nbsp; # make it fill the rest of the disk and mkfs it to clean it out.&nbsp; &nbsp; &nbsp; &nbsp; #&nbsp; &nbsp; &nbsp; &nbsp; echo "Sizing partition 2 (root partition) to use all SD card space..."&nbsp; &nbsp; &nbsp; &nbsp; expand_rootfs&nbsp; &nbsp; &nbsp; &nbsp; mkfs.ext4 $DST_ROOT_PARTITION &gt; /dev/null<br>&nbsp; &nbsp; &nbsp; &nbsp; echo ""&nbsp; &nbsp; &nbsp; &nbsp; echo "/dev/$DST_DISK is initialized and resized. &nbsp;Its partitions are:"# &nbsp; &nbsp; &nbsp; fdisk -l /dev/$DST_DISK | grep $DST_DISK&nbsp; &nbsp; &nbsp; &nbsp; parted /dev/$DST_DISK unit MB p \&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | sed "/^Model/d ; /^Sector/d"<br>&nbsp; &nbsp; &nbsp; &nbsp; SRC_ROOT_VOL_NAME=`e2label /dev/mmcblk0p2`&nbsp; &nbsp; &nbsp; &nbsp; echo ""&nbsp; &nbsp; &nbsp; &nbsp; echo "Your booted /dev/mmcblk0p2 rootfs existing label: $SRC_ROOT_VOL_NAME"&nbsp; &nbsp; &nbsp; &nbsp; echo -n "You may enter a label for the destination rootfs $DST_ROOT_PARTITION: "&nbsp; &nbsp; &nbsp; &nbsp; read resp&nbsp; &nbsp; &nbsp; &nbsp; if [ "$resp" != "" ]&nbsp; &nbsp; &nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e2label $DST_ROOT_PARTITION $resp&nbsp; &nbsp; &nbsp; &nbsp; fi&nbsp; &nbsp; else&nbsp; &nbsp; &nbsp; &nbsp; echo -e "Aborting\n"&nbsp; &nbsp; &nbsp; &nbsp; exit 0&nbsp; &nbsp; fifi</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p># =========== Setup Summary ===========#DST_ROOT_VOL_NAME=`e2label $DST_ROOT_PARTITION`<br>if [ "$DST_ROOT_VOL_NAME" = "" ]then&nbsp; &nbsp; DST_ROOT_VOL_NAME="no label"fi<br>echo ""echo "Clone destination disk &nbsp; : &nbsp;$DST_DISK"echo "Clone destination rootfs : &nbsp;$DST_ROOT_PARTITION ($DST_ROOT_VOL_NAME) on ${CLONE}"echo "Clone destination bootfs : &nbsp;$DST_BOOT_PARTITION on ${CLONE}/boot"echo "Verbose mode &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : &nbsp;$VERBOSE"<br>echo "==============================="</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p># If this is an SD card initialization, can watch progress of the clone# in another terminal with: &nbsp;watch df -h#echo -n "Final check, is it Ok to proceed with the clone (yes/no)?: "read respif [ "$resp" != "y" ] &amp;&amp; [ "$resp" != "yes" ]then&nbsp; &nbsp; echo -e "Aborting the disk clone.\n"&nbsp; &nbsp; exit 0fi<br>## =========== End of Setup &nbsp;===========</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p># Mount destination filesystems.<br>echo "=&gt; Mounting $DST_ROOT_PARTITION ($DST_ROOT_VOL_NAME) on $CLONE"if ! mount $DST_ROOT_PARTITION $CLONEthen&nbsp; &nbsp; echo -e "Mount failure of $DST_ROOT_PARTITION, aborting!\n"&nbsp; &nbsp; exit 0fi<br>if [ ! -d $CLONE/boot ]then&nbsp; &nbsp; mkdir $CLONE/bootfi<br>echo "=&gt; Mounting $DST_BOOT_PARTITION on $CLONE/boot"if ! mount $DST_BOOT_PARTITION $CLONE/bootthen&nbsp; &nbsp; umount $CLONE&nbsp; &nbsp; echo -e "Mount failure of $DST_BOOT_PARTITION, aborting!\n"&nbsp; &nbsp; exit 0fi<br>echo "==============================="</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>START_TIME=`date '+%H:%M:%S'`<br># Exclude fuse mountpoint .gvfs, various other mount points, and tmpfs# file systems from the rsync.#syncecho "Starting the filesystem rsync to $DST_DISK"echo -n "(This may take several minutes)..."rsync $RSYNC_OPTIONS --delete \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '.gvfs' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '/dev' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '/media' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '/mnt' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '/proc' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '/run' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '/sys' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude '/tmp' \&nbsp; &nbsp; &nbsp; &nbsp; --exclude 'lost\+found' \&nbsp; &nbsp; // \&nbsp; &nbsp; $CLONE</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p># Fixup some stuff#<br>for i in dev media mnt proc run sysdo&nbsp; &nbsp; if [ ! -d $CLONE/$i ]&nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; mkdir $CLONE/$i&nbsp; &nbsp; fidone<br>if [ ! -d $CLONE/tmp ]then&nbsp; &nbsp; mkdir $CLONE/tmp&nbsp; &nbsp; chmod a+w $CLONE/tmpfi<br># Some extra optional dirs I create under /mntfor i in $OPTIONAL_MNT_DIRSdo&nbsp; &nbsp; if [ ! -d $CLONE/mnt/$i ]&nbsp; &nbsp; then&nbsp; &nbsp; &nbsp; &nbsp; mkdir $CLONE/mnt/$i&nbsp; &nbsp; fidone<br>rm -f $CLONE/etc/udev/rules.d/70-persistent-net.rules</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>DATE=`date '+%F %H:%M'`<br>echo "$DATE &nbsp;$HOSTNAME $PGM : clone to $DST_DISK ($DST_ROOT_VOL_NAME)" \&nbsp; &nbsp; &nbsp; &nbsp; &gt;&gt; $CLONE_LOGecho "$DATE &nbsp;$HOSTNAME $PGM : clone to $DST_DISK ($DST_ROOT_VOL_NAME)" \&nbsp; &nbsp; &nbsp; &nbsp; &gt;&gt; $CLONE/$CLONE_LOG</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>STOP_TIME=`date '+%H:%M:%S'`<br>echo ""echo "*** Done with clone to /dev/$DST_DISK ***"echo " &nbsp; &nbsp;Started: $START_TIME &nbsp; &nbsp;Finished: $STOP_TIME"echo ""<br># Pause before unmounting in case I want to inspect the clone results# or need to custom modify any files on the destination SD clone.# Eg. modify $CLONE/etc/hostname, $CLONE/etc/network/interfaces, etc# if I'm cloning into a card to be installed on another Pi.#echo -n "Hit Enter when ready to unmount the /dev/$DST_DISK partitions..."read resp<br>echo "unmounting $CLONE/boot"umount $CLONE/boot<br>echo "unmounting $CLONE"umount $CLONE</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>echo "==============================="<br>exit 0</p>
<!-- /wp:paragraph -->

不论有几个分区,把每一个挂载的分区使用umount命令进行卸载:

sudo umount /dev/sda1

如果你不确定sda是不是正确的卡,使用下面的命令列出连接到小派上的卡。

sudo fdisk -l


SD卡插槽上正在运行系统的SD卡应该显示为/dev/mmcblk0。你的空白的SD卡应该显示为/dev/sda1(或者是/dev/sdb1,如果你插入了不止一个USB读卡器到小派上)。

注意你不应该输入”1″ – 如果你看到你的卡显示为”/dev/sda1″,你仍然应该在运行脚本时输入sda(“sda”是卡的名字,而”sda1″是卡的第一个分区的名字)。

现在,你可以开始运行脚本了。

chmod +x rpi-clone.sh
sudo ./rpi_clone sda -f


之前提醒过,第一个参数是SD卡的名字,这里是”sda”。”-f”告诉脚本完整格式化SD卡。

脚本会提示你是否初始化目标SD卡。输入”y”然后按一下回车。

接下来直接按回车

接下来按Y回车

等会就好了。

原创文章,作者:bi4jgm,如若转载,请注明出处:https://showdoi.com/2020.html

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注