Jak mogę skompresować plik w systemie Linux bez używania dodatkowego miejsca na dysku?

20

Mam dysk 100 GB z plikiem 95 GB. Muszę zwolnić trochę miejsca na dysku (a teraz przeniesienie pliku z dysku nie jest opcją). Plik dobrze się skompresuje z, gziplub bz2czymkolwiek, ale wszystkie te programy zapisują skompresowany plik do osobnego pliku. Nie mam na to wystarczającej ilości wolnego miejsca.

Czy istnieje sposób użycia standardowych narzędzi kompresji lub innych narzędzi uniksowych do skompresowania pliku bez użycia dodatkowego miejsca na dysku (lub przynajmniej minimalnej ilości dodatkowego miejsca na dysku)? Wyobrażam sobie coś, co kompresuje część pliku na raz i zapisuje wyniki bezpośrednio nad plikiem. Zdaję sobie sprawę, że byłoby to ryzykowne, ponieważ plik zostałby uszkodzony, gdyby kompresja została przerwana, ale nie sądzę, że mam wybór.

Zawietrzny
źródło
Ostatnią opcją, której używaliśmy w moim starym miejscu, było posiadanie katalogu, który zawierał całą masę plików 1G wypełnionych śmieciami. Następnie, jeśli wpadniesz w szczyptę, możesz usunąć niektóre z nich, aby uzyskać trochę miejsca awaryjnego.

Odpowiedzi:

13

Jest to dowód koncepcyjnego bashu na jeden wiersz, ale powinien zacząć. Używaj na własne ryzyko.

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

Działa to poprzez przesyłanie danych gz do procesu dd, który zapisuje je z powrotem do tego samego pliku. Po zakończeniu plik jest obcinany do rozmiaru wyjścia gz.

Zakłada się, że ostatni wiersz danych wyjściowych dd jest zgodny:

4307 bajtów (4,3 kB) skopiowanych, 2,5855e-05 s, 167 MB / s

Gdzie pierwsze pole jest liczbą całkowitą zapisanych bajtów. Do tego rozmiaru plik będzie musiał zostać obcięty. Nie jestem w 100% pewien, że format wyjściowy jest zawsze taki sam.

użytkownik710307
źródło
Sprytna sztuczka. Czy możesz wyjaśnić, dlaczego conv=notruncjest to konieczne?
śleske,
Może nie jest. gzip -c file | dd of=filewydaje się działać równie dobrze.
user710307,
1
Próbowali tego ludzie z powiązanego pytania (ja też próbowałem); to ogólnie nie działa. Wydaje się, że działa tylko w przypadku bardzo małych plików - być może dlatego, że gzip wczyta mały plik do pamięci RAM przed jego skompresowaniem. W przypadku dużych plików (kilka MB) nie działa, nawet jeśli można je skompresować.
śleske,
3
Tak. Konieczne jest więc conv = notrunc.
user710307
1
Czy nie jest możliwe, że w dowolnym momencie program kompresujący (np. gzip) Zapisuje więcej bajtów nagłówka i danych niż bajtów danych oryginalnych, zastępując w ten sposób niektóre części pliku? Myślę, że to zależy od wybranego programu kompresji. Czy ktoś wpadł na pomysł, jak temu zapobiec lub jak to (nie) prawdopodobne jest?
Daniel Böhmer,
7

To nie tyle gzipi bzip2zastąpić oryginał. Zapisują raczej skompresowane dane na dysk jako nowy plik, a jeśli operacja się powiedzie, odłączają oryginalny nieskompresowany plik.

Jeśli masz wystarczającą ilość pamięci RAM, możesz napisać skrypt, aby tymczasowo skompresować pliki w tmpfssystemie plików, a następnie usunąć oryginał z dysku i zastąpić go skompresowaną wersją. Może coś takiego:

# 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

Pamiętaj tylko o zużyciu pamięci, ponieważ tmpfsjest to zasadniczo dysk RAM. Duży plik wyjściowy może z łatwością zagłodzić system i spowodować inne problemy.

James Sneeringer
źródło
1
To po prostu szalone, żeby zadziałać
Andrew Lambert
Lubię pchać kopertę.
James Sneeringer
3

Nie ma takiego narzędzia, które działałoby w ten sposób, właśnie z tego powodu, który podajesz. Niewiele osób jest skłonnych napisać narzędzie, które celowo wdraża ryzykowne zachowania.

Ignacio Vazquez-Abrams
źródło
Miałem nadzieję, że będzie to niebezpieczna, domyślna opcja dla narzędzia. Czy mógłbyś wymyślić alternatywę? Czy istnieje sposób na obcięcie pliku, aby np. Usunąć pierwsze 2 GB? Pozwoliłoby mi to wykorzystać moją ograniczoną ilość wolnego miejsca do kompresji jednego fragmentu na raz, zmniejszając plik źródłowy podczas pracy.
Lee
Naprawdę nie ma rozsądnego sposobu na usunięcie danych z początku pliku w dowolnym systemie plików, za pomocą dowolnego narzędzia.
Ignacio Vazquez-Abrams
2
Ale możesz usunąć dane z końca pliku. Można to zrobić w zasadzie. Odcinasz dane od końca pliku, aby umieścić je w osobnych plikach, obcinając oryginalne pliki. Następnie kompresujesz pliki w kolejności do przodu, usuwając je z biegiem czasu. Byłoby to trudne do wdrożenia, a jeśli coś pójdzie nie tak, zostaniesz wkręcony. Ale to możliwe.
David Schwartz
1

Poleceń split i csplit można użyć do podzielenia dużego pliku na mniejsze części, a następnie skompresowania ich indywidualnie. Ponowny montaż byłby jednak czasochłonny.

Brian
źródło
Kolejna dobra opcja. Prawdopodobnie można by napisać skrypt, aby to zrobić. Daje to jednak wiele osobno skompresowanych plików, które po dekompresji będą musiały zostać ponownie skonkatenowane, co nie jest tak miłe.
śleske,