![“调整” .img 的大小以适应较小的 SD 卡。如何缩小可启动 SD 卡映像](https://linux22.com/image/915933/%E2%80%9C%E8%B0%83%E6%95%B4%E2%80%9D%20.img%20%E7%9A%84%E5%A4%A7%E5%B0%8F%E4%BB%A5%E9%80%82%E5%BA%94%E8%BE%83%E5%B0%8F%E7%9A%84%20SD%20%E5%8D%A1%E3%80%82%E5%A6%82%E4%BD%95%E7%BC%A9%E5%B0%8F%E5%8F%AF%E5%90%AF%E5%8A%A8%20SD%20%E5%8D%A1%E6%98%A0%E5%83%8F.png)
语境
我有一张 16 GB 的 SD 卡,上面装有基于 Linux 的 Raspberry Pi 操作系统。大部分空间都是空的。
我想与其他人共享 SD .img
,但如果我使用命令
dd if=/dev/sdXX of=/home/user123/SD.img
它将创建一个 16 GB 的图像。太大了。
问题
我怎样才能将 16GB SD 卡图像调整为更小的 4GB?
我已尝试使用 GParted:它可以毫无问题地创建一个 4GB 的分区,但是整个.img
SD 卡仍然为 16 GB,其中有 12 GB 未分配空间。
我已阅读问题和答案在 Ubuntu 中克隆多个分区,但我仍然无法将 16GB SD 卡重新调整为 4GB 卡。
更多信息
~$ lsblk
...
sdc 8:32 1 14,9G 0 disk
├─sdc1 8:33 1 100M 0 part
└─sdc2 8:34 1 4G 0 part
~$ sudo fdisk -l /dev/sdc
Disk /dev/sdc: 14,9 GiB, 15931539456 bytes, 31116288 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xf8a631ce
Device Boot Start End Sectors Size Id Type
/dev/sdc1 * 2048 206847 204800 100M c W95 FAT32 (LBA)
/dev/sdc2 206848 8595455 8388608 4G 83 Linux
任何建议都值得感激!
请注意:正如梅勒比乌斯所观察到的一条评论,正确的用词是收缩:
你不能调整 SD 卡的大小,因为它是具有给定容量的硬件,无法更改。您显然想缩小 SD 卡图像。
答案1
本文给出了解决我的问题的解决方案 (*)。它与另一个非常相似,但它更好地解释了如何计算以及数字和分区的含义。
关键信息是命令的使用truncate
。遵循完整的解决方案以免丢失答案。
初步步骤包括在您的 PC 上克隆 SD 卡:
用于
lsblk
查看哪些设备可用以及它们的分区是否已挂载卸载您要在电脑上复制的设备的所有分区。例如:
umount /dev/sdc1 umount /dev/sdc2
创建整个 SD 卡的副本,并卸载所有分区
dd if=/dev/sdc of=/path/to/file/myimage.img
在 Linux 上缩小图像
问题背景:
具有myimage.img
比硬件支持更大的尺寸(如果尺寸较小则应该没有问题;但是,使用相同的策略,您可以更好地将图像放入硬件支持中)。
秘诀是使用标准 Linux 工具和仪器:GPartedfdisk
和truncate
。
要求:
- Linux 电脑
- 您
.img
想要缩小的(myimage.img
在此示例中)
创建环回设备:
GParted 是一款通常用于管理分区表和文件系统的应用程序。为了收缩图像,GParted 将在答案的第一部分中使用。
GParted 操作的是设备,而不是图像等简单文件。这就是为什么我们首先需要为图像创建一个设备。我们使用 Linux 的环回功能来做到这一点。
让我们启用环回:
sudo modprobe loop
让我们请求一个新的(免费)环回设备:
sudo losetup -f
该命令返回空闲环回设备的路径:
/dev/loop0
让我们创建一个图像的设备:
sudo losetup /dev/loop0 myimage.img
该设备/dev/loop0
代表myimage.img
。我们想要访问映像上的分区,因此我们需要让内核也加载这些分区:
sudo partprobe /dev/loop0
这应该会给我们设备/dev/loop0p1
,它代表中的第一个分区myimage.img
。我们不需要直接使用此设备,但 GParted 需要它。
使用 GParted 调整分区大小:
让我们使用 GParted 加载新设备:
sudo gparted /dev/loop0
当 GParted 应用程序打开时,它应该出现类似以下内容的窗口:
现在请注意以下几点:
- 有一个分区。
- 分区分配整个磁盘/设备/图像。
- 分区已部分填充。
我们希望调整此分区的大小以适合其内容,但不能超过这个大小。
选择分区并点击调整大小/移动。将弹出类似以下的窗口:
尽可能将右侧栏拖到左侧。
请注意,有时 GParted 需要额外的几 MB 空间来放置一些与文件系统相关的数据。您可以按几次新大小框上的向上箭头来执行此操作。例如,我按了 10 次(=10MiB)以使 FAT32 正常工作。对于 NTFS,您可能根本不需要这样做。
最后按“调整大小/移动”。您将返回到 GParted 窗口。这次它看起来类似于以下内容:
请注意,磁盘中有一部分未分配。分区不会使用磁盘的这一部分,因此我们可以稍后从映像中删除这一部分。GParted 是一个磁盘工具,因此它不会缩小映像,只会缩小分区,我们必须自己缩小映像。
按下ApplyGParted。它现在将移动文件并最终缩小分区,因此可能需要一两分钟,但大多数情况下它会很快完成。然后关闭 GParted。
现在我们不再需要环回设备,因此卸载它:
sudo losetup -d /dev/loop0
削减图像:
现在我们已经在映像的开头有了所有重要的数据,是时候删除未分配的部分了。我们首先需要知道分区在哪里结束以及未分配部分在哪里开始。我们使用以下命令执行此操作fdisk
:
fdisk -l myimage.img
在这里我们将看到类似以下内容的输出:
Disk myimage.img: 6144 MB, 6144000000 bytes, 12000000 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000ea37d
Device Boot Start End Blocks Id System
myimage.img1 2048 9181183 4589568 b W95 FAT32
请注意输出中的两件事:
- 分区结束于块 9181183(如下所示
End
) - 块大小为 512 字节(显示为 扇区
1 * 512
)
我们将在示例的其余部分使用这些数字。块大小 (512) 通常相同,但结束块 (9181183) 会有所不同。这些数字表示分区以字节 9181183 结束512 字节。该字节之后是未分配部分。只有前 9181183512 字节对于我们的图像很有用。
接下来,我们将映像文件缩小到刚好可以包含分区的大小。为此,我们将使用命令truncate
(感谢 uggla!)。使用 truncate 命令需要提供文件的大小(以字节为单位)。最后一个块是 9181183,块号从 0 开始。这意味着我们需要 (9181183+1)*512 字节。这很重要,否则分区将不适合映像。所以现在我们使用 truncate 并进行计算:
truncate --size=$[(9181183+1)*512] myimage.img
(*)FrozenCow 的原始帖子似乎已被移动这里。
答案2
所选答案完全适用于系统disklabel 类型。对于谷氨酰胺磷酸酶类型,需要考虑添加 33 个扇区,因为 GPT 也在磁盘末尾存储了一个表。
因此对于 GPT 用户来说,“截断”命令需要如下所示:
截断 --size=$[(最后一个分区结束+1+33)*512]我的图片.img
这应该会在 中产生 GPT 错误fdisk -l
。要修复此问题,请运行以下命令:
gdisk myimage.img
运行命令来验证磁盘:
v
。您应该会看到磁盘上发现一些错误。
“在 gdisk 中,你可以输入X进入专家菜单,然后输入埃将备份分区表数据移动到磁盘的新末尾,然后输入瓦将更改写入磁盘。”[来源]如何在不破坏 GPT 分区表(结束指针)的情况下截断磁盘映像文件中未使用的空间- 谢谢!
答案3
我浏览了这里的许多方法,并理解了它们,但我并不想按顺序执行这些步骤,只是为了缩小 Raspberry Pi IMG 文件。因此,我偶然发现了一个 Bash 脚本,它来自一个名为PiShrink。
执行起来非常简单,并且可以在我的 MacOS M1 Mac Mini 上启动。
背景故事
在我的特殊情况下,我有 2 张 32GB SD 卡,不知什么原因,1 张比另一张小一点(约 95MB),balena蚀刻机拒绝将 IMG 从 2 张 SD 卡中较大的一张写入较小的一张。
我知道我只使用了 32GB 中的约 10GB,因此我可以将 IMG 文件缩小到适合的大小。
脚步
首先,我有以下文件。文件.zip
包含文件.img
,但我在下面显示的是解压后的文件。
$ ls -lh | grep -E 'img|zip'
-rw-r--r-- 1 root staff 28G Jan 29 13:16 backup.zip
--w--wx-w- 1 slm staff 30G Jan 1 1980 disk.img
然后我下载了 PiShrink shell 脚本并使其可执行:
$ wget https://raw.githubusercontent.com/Drewsif/PiShrink/master/pishrink.sh
$ chmod +x pishrink.sh
然后我像这样运行它:
$ sudo pishrink disk.img pi.img
Copying disk.img to pi.img...
e2fsck 1.44.0 (7-Mar-2018)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
STORAGE: 69402/7684096 files (0.2% non-contiguous), 9562823/30732288 blocks
resize2fs 1.44.0 (7-Mar-2018)
resize2fs 1.44.0 (7-Mar-2018)
Resizing the filesystem on /dev/disk4s2 to 9273700 (1k) blocks.
Begin pass 2 (max = 245358)
Relocating blocks XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 3 (max = 3752)
Scanning inode table XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Begin pass 4 (max = 3420)
Updating inode references XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
The filesystem on /dev/disk4s2 is now 9273700 (1k) blocks long.
"disk4" ejected.
fdisk: could not open MBR file /usr/standalone/i386/boot0: No such file or directory
Enter 'help' for information
fdisk: 1> Starting Ending
#: id cyl hd sec - cyl hd sec [ start - size]
------------------------------------------------------------------------
2: 83 1023 3 32 - 1023 254 2 [ 1056768 - 61464576] Linux files*
Partition id ('0' to disable) [0 - FF]: [83] (? for help) Do you wish to edit in CHS mode? [n] Partition offset [0 - 62521344]: [1056768] Partition size [1 - 61464576]: [61464576] fdisk:*1> Writing MBR at offset 0.
fdisk: 1> Shrunk pi.img from 30G to 9.3G
生成的 IMG 文件现在约为 9GB。
$ ls -lh | grep -E 'img|zip'
-rw-r--r-- 1 root staff 28G Jan 29 13:16 backup.zip
--w--wx-w- 1 slm staff 30G Jan 1 1980 disk.img
--w---x--- 1 root staff 9.4G Jan 29 17:04 pi.img
然后我将其重新打包为 ZIP 文件,以便在磁盘上处理时保持最有效的大小。
$ sudo zip pi.zip pi.img
我们现在有以下一组文件:
$ ls -lh | grep -E 'img|zip'
-rw-r--r-- 1 root staff 28G Jan 29 13:16 backup.zip
--w--wx-w- 1 slm staff 30G Jan 1 1980 disk.img
--w---x--- 1 root staff 9.4G Jan 29 17:04 pi.img
-rw-r--r-- 1 root staff 8.3G Jan 29 17:08 pi.zip
然后我可以使用balena蚀刻机或者ApplePi-Baker将 ZIP 文件刻录到“较小”的 SD 卡。
查看我的 Mac 上的 SD 卡时,我看到它显示约 10GB。
$ diskutil list /dev/disk4
/dev/disk4 (external, physical):
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *31.9 GB disk4
1: Windows_FAT_32 LIBREELEC 536.9 MB disk4s1
2: Linux 10.0 GB disk4s2
(free space) 21.3 GB -
笔记:我可以使用 etc. 从 Linux 系统执行相同的命令lsblk
。
术后
使用上述方法后,我确实注意到 SD 卡内的文件系统在 32GB 上不够用。主要表现如下:
$ df -h | grep -E "File|mmc"
Filesystem Size Used Available Use% Mounted on
/dev/mmcblk0p1 511.7M 141.7M 370.0M 28% /flash
/dev/mmcblk0p2 8.6G 8.2G 377.4M 96% /storage
重新启动后,通过从内部扩展 SD 文件系统应该可以轻松解决这个问题。
首先我使用以下命令parted
来扩展分区:
$ parted /dev/mmcblk0 resizepart 2 100%
Warning: Partition /dev/mmcblk0p2 is being used. Are you sure you want to
continue?
Yes/No? yes
yes
Information: You may need to update /etc/fstab.
然后我重新启动了系统:
$ reboot
之后我使用以下命令在线扩展了文件系统resize2fs
:
$ resize2fs /dev/mmcblk0p2
resize2fs 1.45.6 (20-Mar-2020)
Filesystem at /dev/mmcblk0p2 is mounted on /storage; on-line resizing required
old_desc_blocks = 71, new_desc_blocks = 234
The filesystem on /dev/mmcblk0p2 is now 30638592 (1k) blocks long.
现在显示 SD 卡上的所有可用空间:
$ df -h | grep -E "File|mmc"
Filesystem Size Used Available Use% Mounted on
/dev/mmcblk0p1 511.7M 141.7M 370.0M 28% /flash
/dev/mmcblk0p2 28.3G 8.2G 20.1G 29% /storage