Как изменить размер файла img, созданного с помощью dd?
У меня есть изображение DD с SD-карты 4 ГБ, которая имеет два раздела, эти два раздела занимают всего около 800 МБ, и поэтому я хочу уменьшить размер IMG-файла.
Кто-нибудь знает способ удаления "свободного места" из файла img?
8 ответов
Сначала убедитесь, что свободное место на самом деле пусто и не содержит остатков удаленных файлов. Самый простой способ добиться этого - создать на диске огромный файл, содержащий только нулевые байты, а затем удалить его.
# losetup --find --partscan foo.img
# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop0 7:0 0 4096M 0 loop
├─loop0p1 259:0 0 2048M 0 loop
└─loop0p2 259:1 0 2048M 0 loop
# for part in /dev/loop0p*; do
mount $part /mnt
dd if=/dev/zero of=/mnt/filler conv=fsync bs=1M
rm /mnt/filler
umount /mnt
done
dd: error writing ‘/mnt/filler’: No space left on device
dd: error writing ‘/mnt/filler’: No space left on device
# losetup --detach /dev/loop0
Затем сожмите его с помощью инструмента, как gzip
или же xz
, Даже при самых низких уровнях сжатия длинная серия нулей будет хорошо сжиматься:
# ls -s
4096M foo.img
# gzip foo.img
# ls -s
11M foo.img.gz
Обратите внимание, что вы должны распаковать изображение при записи его обратно на диск. Это распакует его "вживую":
# cat foo.img.gz | gunzip | dd of=/dev/sda
Обратите внимание, что выходное устройство (sda) должно быть достаточного размера, чтобы соответствовать исходному изображению, в противном случае данные будут потеряны или повреждены.
Альтернативный метод, если вы хотите продолжать использовать образ - например, с виртуальной машиной - это преобразовать необработанный образ в один из форматов изображений, используемых программным обеспечением для виртуализации; например, qcow2 для Qemu, VDI для VirtualBox или VMDK для VMware.
Обратите внимание, что для этого по- прежнему требуется подготовить изображение, очистив свободное место, используя вышеуказанный метод.
# qemu-img convert -f raw -O qcow2 foo.img foo.qcow
# qemu-img convert -f raw -O vmdk foo.img foo.vmdk
Но если он снова будет записан на реальный диск, вам придется преобразовать его обратно в необработанный образ.
С помощью resize2fs
намного намного легче
resize2fs -M xxx.img
Сначала вас попросят e2fsck - так:
e2fsck -f -y xxx.img
(изображение НЕ должно быть смонтировано!)
Примечание: это будет работать, только если изображение состоит из одного раздела, если это целое блочное устройство с несколькими разделами, см. Ответ выше...
Первоначально я разместил тот же ответ здесь, на StackExchange. Спросите Ubuntu. Я повторно предлагаю тот же ответ здесь, он может быть полезен.
Ключевой информацией было использование команды. Следуем полному решению, чтобы не потерять ответ.
Предварительный шаг заключается в клонировании SD-карты на вашем ПК:
использовать
lsblk
чтобы увидеть, какие устройства доступны и смонтированы ли их разделыотключите все разделы устройства, которое вы хотите скопировать, на свой компьютер. Например:
umount /dev/sdc1 umount /dev/sdc2
создайте копию всей SD-карты со всеми отключенными разделами
dd if=/dev/sdc of=/path/to/file/myimage.img
Сжатие изображений в Linux
Контекст проблемы:
Имея больше, чем аппаратная поддержка (если она меньше, проблем быть не должно; однако, используя ту же стратегию, вы можете лучше разместить изображение в аппаратной поддержке).
Секрет в том, чтобы использовать стандартные инструменты и средства Linux: GParted и .
Требования:
- ПК с Linux
- The
.img
вы хотите сжать (в этом примере)
Создание устройства обратной связи:
GParted — это приложение, обычно используемое для управления таблицами разделов и файловыми системами. Чтобы уменьшить изображение, в первой части ответа будет использоваться GParted.
GParted работает с устройствами, а не с простыми файлами, такими как изображения. Вот почему нам сначала нужно создать устройство для изображения. Мы делаем это, используя функцию обратной связи Linux.
Давайте включим петлю:
sudo modprobe loop
Давайте запросим новое (бесплатное) устройство обратной связи:
sudo losetup -f
Команда возвращает путь к устройству свободного шлейфа:
/dev/loop0
Создадим устройство изображения:
sudo losetup /dev/loop0 myimage.img
Устройство/dev/loop0
представляет . Мы хотим получить доступ к разделам, которые есть в образе, поэтому нам нужно попросить ядро загрузить и их:
sudo partprobe /dev/loop0
Это должно дать нам устройство/dev/loop0p1
, который представляет первый раздел вmyimage.img
. Нам это устройство напрямую не нужно, но оно требуется для GParted.
Измените размер раздела с помощью GParted:
Давайте загрузим новое устройство с помощью GParted:
sudo gparted /dev/loop0
Когда откроется приложение GParted, должно появиться окно, подобное следующему:
Теперь обратите внимание на несколько вещей:
- Есть один раздел.
- В разделе выделяется весь диск/устройство/образ.
- Раздел заполнен частично.
Мы хотим изменить размер этого раздела так, чтобы он соответствовал его содержимому, но не более того.
Выберите раздел и нажмите «Изменить размер/переместить». Появится окно, подобное следующему:
Перетащите правую полосу влево как можно дальше.
Обратите внимание, что иногда GParted потребуется несколько дополнительных МБ для размещения некоторых данных, связанных с файловой системой. Для этого можно несколько раз нажать стрелку вверх в поле «Новый размер». Например, я нажал ее 10 раз (=10 МБ), чтобы FAT32 заработал. Для NTFS вам это может вообще не понадобиться.
Наконец нажмите «Изменить размер/переместить». Вы вернетесь в окно GParted. На этот раз это будет выглядеть примерно так:
Обратите внимание, что часть диска нераспределена. Эта часть диска не будет использоваться разделом, поэтому мы сможем удалить эту часть образа позже. GParted — это инструмент для дисков, поэтому он не сжимает образы, а только разделы, нам приходится сжимать образ самостоятельно.
Нажмите Applyв GParted. Теперь он переместит файлы и, наконец, уменьшит раздел, поэтому это может занять минуту или две, но в большинстве случаев все заканчивается быстро. После этого закройте 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) будет для вас другим. Цифры означают, что раздел заканчивается на байте 9181183512 файла. После этого байта идет нераспределенная часть. Для нашего изображения будут полезны только первые 9181183 512 байт.
Затем мы сжимаем файл изображения до размера, который может содержать только раздел. Для этого мы будем использоватьtruncate
команда (спасибо, уггла!). С помощью команды truncate необходимо указать размер файла в байтах. Последний блок имел номер 9181183, а номера блоков начинаются с 0. Это означает, что нам нужно (9181183+1)*512 байт. Это важно, иначе раздел не поместится в образ. Итак, теперь мы используем усечение при вычислениях:
truncate --size=$[(9181183+1)*512] myimage.img
Я также попробовал это с qemu-img, и это сработало как шарм:
qemu-img resize test.img 2G
Мы изменяем размеры test.img
сделать это 2G (2GB).
Работал безупречно для меня.
Я использовал подход gparted с моим компьютером Ubuntu 16.10:
1) Сопоставьте файл img со следующим доступным разделом цикла с помощью losetup
, как описано в предыдущих постах, как указано выше
2) Проверьте с lsblk
к какому дисковому циклу привязан ваш файл изображения, например /dev/loop0
3) Выполнить sudo gparted /dev/loop0
4) Сократите раздел (ы) петли, если считаете это необходимым; Пожалуйста, убедитесь, что эти разделы отключены.
5) Выполнить fdisk /dev/loop0
затем введите p
, это покажет вам размер блока и номер конечного блока различных разделов.
6) Выполнить dd if=/dev/loop0 of=shrunk_image_file.img
, примените к этой команде параметры bs=[BlockSize]
а также count=[EndBlockNumberOfLastLoopPartition+1]
и у вас будет сжатый и правый файл изображения.
Сделал что-то в ответ на это https://github.com/bbaranoff/PimpMyOPi Должно быть не только на OrangePi5 :)Don 39;не забудьте установить qemu. Вы можете выполнить chroot в системе только в том случае, если /bin/bash находится в part2 во время записи :(
Просмотрел многие методы здесь и понял их все, но мне не хотелось выполнять эти шаги, поскольку мне приходилось выполнять их по очереди, чтобы просто сжать IMG-файл Raspberry Pi. Итак, глядя, я наткнулся на этот сценарий Bash из проекта под названием PiShrink , о котором Huan упомянул здесь в своем ответе . Я принял его предложение и полностью применил PiShrink.
ПРИМЕЧАНИЕ. Выполнить это было довольно просто, и при загрузке моего MacOS M1 Mac Mini это работало.
Предыстория
В моем конкретном случае у меня было 2 SD-карты по 32 ГБ, и по какой-то причине одна была немного (~95 МБ) меньше другой, и отказался записывать IMG с большей из двух SD-карт на меньшую.
Я знал, что использую только ~10 ГБ из 32 ГБ, чтобы можно было сжать файл 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 и сделал его исполняемым:
$ 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 теперь занимает ~9 ГБ.
$ 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
Затем я могу использовать balenaEtcherbalenaEtcher или ApplePi-Baker, чтобы записать ZIP-файл на «меньшую» SD-карту.
Покопавшись в SD-карте на моем Mac, я вижу, что на ней около 10 ГБ.
$ 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 -
ПРИМЕЧАНИЕ. Я мог бы выполнять те же команды из системы Linux, используяlsblk
и т. д..
Послеоперационный период
После использования описанного выше метода я заметил, что файловой системе на SD-карте не хватает полных 32 ГБ. В основном это выглядело так:
$ 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