Как изменить размер файла 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-карты на вашем ПК:

  1. использоватьlsblkчтобы увидеть, какие устройства доступны и смонтированы ли их разделы

  2. отключите все разделы устройства, которое вы хотите скопировать, на свой компьютер. Например:

             umount /dev/sdc1
     umount /dev/sdc2
    
  3. создайте копию всей 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] и у вас будет сжатый и правый файл изображения.

Если вы работаете с изображением Raspberry Pi, то можете попробовать pishrink: он очень прост в использовании и автоматически минимизирует файл изображения Pi.

Сделал что-то в ответ на это 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
Другие вопросы по тегам