Skutecznie usuń plik (i) z dużego pliku .tgz

14

Załóżmy, że mam skompresowany przez gzip plik tar-ball CompressedArchive.tgz (+100 plików, łącznie + 5 gb).

Jaki byłby najszybszy sposób, aby usunąć wszystkie wpisy pasujące do wzorca nazwy pliku, na przykład przedrostek * .jpg, a następnie zapisać resztki w gzip: ed tar-ball?

Zastąpienie starego archiwum lub utworzenie nowego nie jest ważne, w zależności od tego, co nastąpi najszybciej.

Aksel Willgert
źródło

Odpowiedzi:

14

Dzięki GNU tarmożesz:

pigz -d < file.tgz |
  tar --delete --wildcards -f - '*/prefix*.jpg' |
  pigz > newfile.tgz

Z bsdtar:

pigz -d < file.tgz |
  bsdtar -cf - --exclude='*/prefix*.jpg' @- |
  pigz > newfile.tgz

( pigzbędąca wersją wielowątkową gzip).

Możesz nadpisać sam plik, tak jak:

{ pigz -d < file.tgz |
    tar --delete --wildcards -f - '*/prefix*.jpg' |
    pigz &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file.tgz

Jest to jednak dość ryzykowne, zwłaszcza jeśli wynik jest mniej skompresowany niż oryginalny plik (w takim przypadku drugi pigzmoże ostatecznie zastąpić obszary pliku, których pierwszy jeszcze nie przeczytał).

Stéphane Chazelas
źródło
dziękuję za odpowiedź, głosowałem. uruchomię test porównawczy w przyszłym tygodniu, aby sprawdzić, który z nich działa lepiej w moim archiwum i systemie, i zaakceptuj to.
Aksel Willgert
8

Nie dyskontuj w prosty sposób: może być wystarczająco szybki dla twojego celu. Z avfs, aby uzyskać dostęp do archiwum jako katalogu:

cd ~/.avfs/path/to/original.tar.gz\#
pax -w -s '/^.*\.jpg$//' | gzip >/path/to/filtered.tar.gz        # POSIX
tar -czf /path/to/filtered.tar.gz -s '/^.*\.jpg$//' .            # BSD
tar -czf /path/to/filtered.tar.gz --transform '/^.*\.jpg$//' .   # GNU

Korzystając z bardziej prymitywnych narzędzi, najpierw wyodrębnij pliki z wyłączeniem .jpgplików, a następnie utwórz nowe archiwum.

mkdir tmpdir && cd tmpdir
<original.tar.gz gzip -d | pax -r -pe -s '/^.*\.jpg$//'
pax -w . | gzip >filtered.tar.gz
cd .. && rm -rf tmpdir

Jeśli twoja smoła ma --exclude:

mkdir tmpdir && cd tmpdir
tar -xzf original.tar.gz --exclude='*.jpg'
tar -czf filtered.tar.gz .
cd .. && rm -rf tmpdir

Może to jednak zaburzać własność i tryby plików, jeśli nie uruchomisz go jako root. Aby uzyskać najlepsze wyniki, użyj katalogu tymczasowego w szybkim systemie plików - tmpfs, jeśli masz wystarczająco duży.

Wsparcie dla archiwizatorów działających jako tranzyt (tj. Czytaj archiwum i zapisuj archiwum) jest zwykle ograniczone. GNU tar może usuwać członków z archiwum za pomocą --deleteopcji operacji („Zgłoszono, że --deleteopcja działa poprawnie, gdy tardziała jak filtr od stdindo stdout.”), I to prawdopodobnie najlepsza opcja.

Możesz stworzyć potężne filtry archiwalne w kilku wierszach Pythona. Jego tarfilebiblioteka może odczytywać i zapisywać z niewidocznych strumieni, a także można używać dowolnego kodu w Pythonie do filtrowania, zmieniania nazw, modyfikowania…

#!/usr/bin/python
import re, sys, tarfile
source = tarfile.open(fileobj=sys.stdin, mode='r|*')
dest = tarfile.open(fileobj=sys.stdout, mode='w|gz')
for member in source:
    if not (member.isreg() and re.match(r'.*\.jpg\Z', member.name)):
        sys.stderr.write(member.name + '\n')
        dest.addfile(member, source.extractfile(member))
dest.close()
Gilles „SO- przestań być zły”
źródło
Zmieniłby również nazwy użytkowników / użytkowników, gdyby działał jako root, chyba że jest to zrobione na komputerze, który ma takie samo odwzorowanie nazwy użytkownika <=>, jak ten, na którym plik tar został pierwotnie utworzony. Listy ACL, atrybuty rozszerzone również mogą zostać naruszone. Za pomocą tarmożesz dodać popcję.
Stéphane Chazelas
2

Dzięki tarowi dostępnemu w Mac OSX możesz to zrobić:

tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz
Jake
źródło
1

Aby to zrobić, prawdopodobnie musisz wyodrębnić całą zawartość pliku .tgz w lokalnym katalogu, a następnie usunąć niepotrzebne pliki, a następnie ponownie skompresować plik .tgz.

Jest długi i potrzebujesz wystarczającej ilości wolnego miejsca na dysku, ale o ile mi wiadomo, nie ma innego sposobu, aby to zrobić.

Ponieważ masz już taką ścieżkę z /tmpdir/withalotofspacewystarczającą ilością wolnego miejsca (sprawdź to za pomocą df -h /tmpdir/withalotofspace), możesz zrobić coś takiego:

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .
DavAlPi
źródło
Jak pokazują inne odpowiedzi, dzięki potokowi w żadnym momencie nie ma potrzeby przechowywania nieskompresowanych danych na dysku
Tobias Kienzler
0

Podoba mi się odpowiedź @Gilles, ale można ją jeszcze bardziej uprościć. Na przykład po rozpakowaniu gunzip foo.tgzplik będzie foo.tari pliki można usunąć za pomocą tar -f foo.tar --delete file|directory. Poniżej znajduje się przykład usuwania katalogu z pliku tar.

    phablet@ubuntu-phablet:~/Downloads$ tar -cvf moo.tar moo1/
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -f moo.tar --delete "moo1/moo2/moo3"
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/

Określone typy plików można znaleźć za pomocą tar -tf foo.tar|egrep -i '.jpg$'.

Funmungus
źródło