Jak połączyć wiele skompresowanych plików w jedno archiwum?

10

Mam kilkaset .tar.xzplików, które są prawie identyczne (są to codzienne zrzuty bazy danych, a baza danych zmienia się powoli).

Uważam, że ze względu na podobieństwa w nieskompresowanych plikach będą one bardzo dobrze kompresować, a testy na małą skalę wykazały, że kompresja dowolnej liczby tych nieskompresowanych plików tworzy archiwum tylko nieco większe niż jeden z nich.

Mój problem polega na tym, że wszystkie nieskompresowane pliki miałyby kilka terabajtów (współczynnik kompresji wynosi około 25: 1), a ja nie mam tyle miejsca na dysku, aby wykorzystać je jako obszar roboczy.

Czy istnieje sposób, w jaki mogę przetwarzać poszczególne skompresowane pliki pojedynczo, dodając je do jednego archiwum i zachowując zalety kompresji ich razem?

jl6
źródło
Czy próbowałeś skryptować go, aby rozpakować jeden plik, dodać wszystkie pliki do danego archiwum, a następnie przejść do następnego?
darnir

Odpowiedzi:

10

Ponieważ pliki tar są formatem przesyłania strumieniowego - możesz catdwa z nich razem i uzyskać prawie poprawny wynik - nie musisz wcale rozpakowywać ich na dysk, aby to zrobić. Możesz dekompresować (tylko) pliki, połączyć je razem i ponownie skompresować ten strumień:

xzcat *.tar.xz | xz -c > combined.tar.xz

combined.tar.xzbędzie skompresowanym archiwum wszystkich plików w składowych archiwach, które jest tylko nieznacznie uszkodzone. Aby wyodrębnić, będziesz musiał użyć --ignore-zerosopcji (w GNU tar), ponieważ archiwa mają znacznik „końca pliku”, który pojawi się w środku wyniku. Poza tym wszystko będzie działać poprawnie.

GNU tarobsługuje także --concatenatetryb tworzenia połączonych archiwów. Ma to te same ograniczenia co powyżej - musisz użyć --ignore-zerosdo wypakowania - ale to nie działa ze skompresowanymi archiwami. Możesz zbudować coś, co zmusi go do działania przy użyciu zastępowania procesów, ale jest to kłopotliwe i jeszcze bardziej kruche.

Jeśli istnieją pliki, które pojawiają się więcej niż jeden raz w różnych plikach tar, nie będzie to działać poprawnie, ale mimo to masz problem. W przeciwnym razie da ci to, czego chcesz - przepuszczanie danych wyjściowych xzjest sposobem tarkompresji danych wyjściowych.


Jeśli archiwa, które działają tylko z konkretną tarimplementacją, nie są odpowiednie do twoich celów, dołącz do archiwum z rtwoim przyjacielem:

tar cJf combined.tar.xz dummy-file
for x in db-*.tar.xz
do
    mkdir tmp
    pushd tmp
    tar xJf "../$x"
    tar rJf ../combined.tar.xz .
    popd
    rm -r tmp
done

To zawsze wyodrębnia tylko jedno archiwum na raz, więc przestrzeń robocza jest ograniczona do wielkości zawartości pojedynczego archiwum. Kompresja jest przesyłana strumieniowo, tak jak w przypadku, gdybyś utworzył ostateczne archiwum naraz, więc będzie tak dobry, jak mógł być kiedykolwiek. Robisz dużo nadmiaru dekompresji i rekompresji, co spowoduje, że będzie to wolniejsze niż catwersje, ale archiwum wynikowe będzie działać w dowolnym miejscu bez specjalnego wsparcia.

Zauważ, że - w zależności od tego, czego dokładnie chcesz - wystarczy samo dodanie nieskompresowanych plików tar do archiwum. Będą kompresować (prawie) dokładnie tak samo, jak ich zawartość w jednym pliku, a to zmniejszy narzut kompresji dla każdego pliku. To wyglądałoby mniej więcej tak:

tar cJf combined.tar.xz dummy-file
for x in db-*.tar.xz
do
    xz -dk "$x"
    tar rJf combined.tar.xz "${x%.xz}"
    rm -f "${x%.xz}"
done

Jest to nieco mniej wydajne pod względem końcowego skompresowanego rozmiaru, ponieważ w strumieniu są dodatkowe nagłówki tar, ale oszczędza trochę czasu na rozpakowywaniu i ponownym dodawaniu wszystkich plików jako plików. Skończyło się na tym, że combined.tar.xzzawiera wiele (nieskompresowanych) db-*.tarplików.

Michael Homer
źródło
Dzięki, twoja druga opcja wydaje się odpowiednia dla mojego celu, ale czy mógłbyś rozwinąć swój ostatni akapit? Jak by to wyglądało?
jl6
@ jl6: Zobacz edycję.
Michael Homer
Przepraszamy, tylko mogłem to przetestować. Druga metoda daje mi ten błąd:tar: Cannot update compressed archives
jl6,