Как я могу сжать файл в Linux на месте, не используя дополнительное место на диске?

20

У меня есть диск на 100 ГБ, который имеет файл на 95 ГБ. Мне нужно освободить место на диске (и сейчас перенос файла с диска не возможен). Файл будет хорошо сжиматься gzipили bz2каким-либо другим образом, но все эти программы записывают сжатый файл в отдельный файл. У меня недостаточно свободного места для этого.

Есть ли способ использовать стандартные инструменты сжатия или другие утилиты Unix для сжатия файла без использования дополнительного дискового пространства (или хотя бы минимального дополнительного дискового пространства)? Я представляю что-то, что сжимает часть файла за раз и записывает результаты прямо в файл. Я понимаю, что это было бы рискованно, поскольку файл был бы поврежден, если сжатие было прервано, но я не думаю, что у меня есть выбор.

подветренный
источник
Последний вариант, который мы использовали в моем старом месте, заключался в том, чтобы где-то иметь каталог, содержащий целую кучу файлов 1G, заполненных мусором. Затем, если вы попали в крайнее положение, вы можете удалить некоторые из них, чтобы дать вам немного места для экстренных ситуаций.

Ответы:

13

Это доказательство концепции bash one-liner, но оно должно помочь вам начать. Используйте на свой риск.

truncate -s `gzip -c file | dd of=file conv=notrunc 2>&1 | sed -n '$ s/ .*$// p'` file
mv file file.gz

Это работает путем передачи данных gz в процесс dd, который записывает их обратно в тот же файл. После завершения файл усекается до размера вывода gz.

Это предполагает, что последняя строка вывода dd соответствует:

Скопировано 4307 байт (4,3 кБ), 2,5855e-05 с, 167 МБ / с

Где первое поле является целым числом записанных байтов. Это размер, до которого файл нужно будет обрезать. Я не уверен на 100%, что формат вывода всегда один и тот же.

user710307
источник
Отличный трюк. Не могли бы вы объяснить, почему conv=notruncэто необходимо?
слеске
Возможно это не так. gzip -c file | dd of=fileкажется, работает так же хорошо.
user710307
1
Люди по связанному вопросу попробовали это (и я попробовал это также); это не работает в целом. Кажется, это работает только для очень маленьких файлов - возможно, потому что gzip будет читать маленький файл в оперативную память перед сжатием. Для больших файлов (несколько МБ) это не работает, даже если они сжимаются.
слеське
3
Ага. Так что conv = notrunc необходим.
user710307
1
Разве не возможно, что в любое время программа сжатия (например gzip) записывает больше байтов заголовка и данных, чем байтов исходных данных, таким образом перезаписывая некоторые части файла? Я думаю, это зависит от выбранной программы сжатия. Кто-нибудь знает, как предотвратить это или насколько (вероятно) это возможно?
Даниэль Бёмер
7

Это не так уж много, gzipи bzip2переписать оригинал. Вместо этого они записывают сжатые данные на диск в виде нового файла, и, если эта операция завершается успешно, они отменяют связь с исходным несжатым файлом.

Если у вас достаточно ОЗУ, вы можете написать скрипт для временного сжатия файлов в tmpfsфайловой системе, а затем удалить оригинал на диске и заменить его сжатой версией. Может быть, что-то вроде этого:

# some distributions mount /dev/shm as tmpfs; replace with bzip2 if you prefer
if gzip -q9c /full/disk/somefile > /dev/shm/somefile.gz
then
    rm -f /full/disk/somefile && mv -i /dev/shm/somefile.gz /full/disk
fi

Просто помните об использовании памяти, так tmpfsкак по сути это RAM-диск. Большой выходной файл может легко заморозить систему и вызвать другие проблемы для вас.

Джеймс Снерингер
источник
1
Это просто сумасшествие, чтобы работать
Эндрю Ламберт
Мне нравится раздвигать конверт.
Джеймс Снирингер
3

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

Игнасио Васкес-Абрамс
источник
Я надеялся, что это будет небезопасный, нестандартный вариант для утилиты. Не могли бы вы придумать альтернативу? Есть ли способ обрезать файл на месте, например, чтобы удалить первые 2 ГБ? Это позволило бы мне использовать мое ограниченное свободное пространство для сжатия по одному куску за раз, сокращая исходный файл по мере продвижения.
Ли
На самом деле нет никакого разумного способа удалить данные из начала файла в любой файловой системе, с помощью любого инструмента.
Игнасио Васкес-Абрамс
2
Но вы можете удалить данные из конца файла. Это можно сделать в принципе. Вы отсекаете данные от конца файла, чтобы поместить их в отдельные файлы, обрезая исходные файлы по ходу работы. Затем вы сжимаете файлы в прямом порядке, удаляя их по ходу работы. Это было бы трудно реализовать, и если что-то пошло не так, вы бы облажались. Но это возможно.
Дэвид Шварц
1

Команды split и csplit можно использовать для разбиения большого файла на более мелкие части, а затем для их индивидуального сжатия. Сборка будет довольно трудоемкой, хотя.

Брайан
источник
Еще один хороший вариант. Можно было бы написать какой-нибудь скрипт для этого. Тем не менее, это дает много отдельно сжатых файлов, которые нужно будет повторно объединять после распаковки, что не очень хорошо.
слеске