Rimuovi in ​​modo efficiente i file da .tgz di grandi dimensioni


14

Supponiamo di avere un tar-ball compresso con gzip compressedArchive.tgz (+100 file, per un totale di + 5 gb).

Quale sarebbe il modo più veloce per rimuovere tutte le voci corrispondenti a un determinato modello di file, ad esempio il prefisso * .jpg, e quindi memorizzare di nuovo i resti in un tar gzip: ed tar?

Sostituire il vecchio archivio o crearne uno nuovo non è importante, qualunque sia il più veloce.


Risposte:


14

Con GNU tarpuoi fare:

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

Con bsdtar:

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

(pigz essendo la versione multi-thread di gzip).

È possibile sovrascrivere il file su se stesso come:

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

Ma è abbastanza rischioso, specialmente se il risultato finisce per essere meno compresso rispetto al file originale (nel qual caso, il secondo pigzpotrebbe finire per sovrascrivere aree del file che il primo non ha ancora letto).


grazie per la risposta, votato. eseguirà benchmark la prossima settimana per vedere quale si comporta meglio per il mio archivio e sistema e accettarlo.
Aksel Willgert,

8

Non fare sconti in modo semplice: potrebbe essere abbastanza veloce per il tuo scopo. Con avfs per accedere all'archivio come directory:

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

Con strumenti più primitivi, prima estrai i file escludendo i .jpgfile, quindi crea un nuovo archivio.

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

Se il tuo tar ha --exclude:

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

Ciò può tuttavia manipolare la proprietà e le modalità del file se non lo si esegue come root. Per i migliori risultati, usa una directory temporanea su un filesystem veloce - tmpfs se ne hai uno abbastanza grande.

Il supporto degli archivi per agire da pass-through (ovvero leggere un archivio e scrivere un archivio) tende ad essere limitato. Tar GNU può eliminare membri da un archivio con l' --deleteopzione operativa (“È --deletestato segnalato che l'opzione funziona correttamente quando tarfunge da filtro da stdinastdout ."), E questa è probabilmente l'opzione migliore.

Puoi creare potenti filtri di archiviazione in poche righe di Python. La sua tarfilelibreria può leggere e scrivere da flussi non ricercabili e puoi usare codice arbitrario in Python per filtrare, rinominare, modificare ...

#!/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()

Manipolerebbe anche uid / nomi utente se eseguito come root a meno che non venga eseguito su una macchina che abbia lo stesso uid <=> mapping nome utente di quello in cui è stato inizialmente creato il file tar. ACL, possono essere interessati anche gli attributi estesi. Con tar, potresti voler aggiungere l' popzione.
Stéphane Chazelas,

2

Con il tar che viene su Mac OSX, puoi fare questo:

tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz

1

Per fare questo, probabilmente devi estrarre tutto il contenuto del file .tgz in una directory locale, quindi cancellare i file che non vuoi quindi ricomprimere il .tgz.

È lungo e hai bisogno di sufficiente spazio libero su disco ma, per quanto ne sappia, non c'è altro modo per farlo.

Dato che hai già un percorso come /tmpdir/withalotofspacequello che ha spazio libero sufficiente (controllalo usando df -h /tmpdir/withalotofspace), puoi fare qualcosa del genere:

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .

Come mostrano le altre risposte, attraverso il piping non è necessario archiviare i dati non compressi sul disco in qualsiasi momento
Tobias Kienzler,

0

Mi piace la risposta di @Gilles, tranne che può essere ulteriormente semplificata. Dopo aver decompresso, ad esempio, gunzip foo.tgzil file sarà foo.tare i file potranno essere rimossi con tar -f foo.tar --delete file|directory. Di seguito è riportato un esempio di rimozione di una directory da un file 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/

È possibile trovare tipi di file specifici con tar -tf foo.tar|egrep -i '.jpg$'.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.