Supprimez efficacement les fichiers des grands fichiers .tgz

14

Supposons que j'ai un tar-ball compressé gzip compresséArchive.tgz (+100 fichiers, totalisant + 5 Go).

Quel serait le moyen le plus rapide de supprimer toutes les entrées correspondant à un modèle de nom de fichier donné, par exemple le préfixe * .jpg, puis de stocker à nouveau les restes dans une tar-ball gzip: ed?

Le remplacement de l'ancienne archive ou la création d'une nouvelle n'est pas important, selon la plus rapide.

Aksel Willgert
la source

Réponses:

14

Avec GNU tar, vous pouvez faire:

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

Avec bsdtar:

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

( pigzétant la version multi-thread de gzip).

Vous pouvez écraser le fichier sur lui-même comme:

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

Mais c'est assez risqué, surtout si le résultat finit par être moins compressé que le fichier d'origine (dans ce cas, le second pigzpeut finir par écraser les zones du fichier que le premier n'a pas encore lues).

Stéphane Chazelas
la source
merci pour la réponse, a voté. exécutera un benchmark la semaine prochaine pour voir lequel fonctionne le mieux pour mes archives et mon système et accepter cela.
Aksel Willgert
8

Ne négligez pas la manière simple: elle peut être assez rapide pour votre objectif. Avec avfs pour accéder à l'archive en tant que répertoire:

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

Avec des outils plus primitifs, extrayez d'abord les fichiers à l'exclusion des .jpgfichiers, puis créez une nouvelle archive.

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

Si votre goudron a --exclude:

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

Cela peut cependant modifier la propriété et les modes du fichier si vous ne l'exécutez pas en tant que root. Pour de meilleurs résultats, utilisez un répertoire temporaire sur un système de fichiers rapide - tmpfs si vous en avez un assez grand.

La prise en charge des archiveurs pour agir en tant qu'intermédiaire (c'est-à-dire lire une archive et écrire une archive) a tendance à être limitée. GNU tar peut supprimer des membres d'une archive avec l' --deleteoption operation («L' --deleteoption a été rapportée pour fonctionner correctement lorsqu'elle taragit comme un filtre de stdinà stdout.»), Et c'est probablement votre meilleure option.

Vous pouvez créer des filtres d'archivage puissants dans quelques lignes de Python. Sa tarfilebibliothèque peut lire et écrire à partir de flux non recherchés, et vous pouvez utiliser du code arbitraire en Python pour filtrer, renommer, modifier…

#!/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- arrête d'être méchant'
la source
Il gèrerait également uid / usernames s'il était exécuté en tant que root, sauf s'il est effectué sur une machine qui a le même mappage de nom d'utilisateur uid <=> que celui sur lequel le fichier tar a été initialement créé. Les ACL et les attributs étendus peuvent également être affectés. Avec tar, vous souhaiterez peut-être ajouter l' poption.
Stéphane Chazelas
2

Avec le tar qui vient sur Mac OSX, vous pouvez faire ceci:

tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz
Jake
la source
1

Pour ce faire, vous devrez probablement extraire tout le contenu du fichier .tgz dans un répertoire local puis effacer les fichiers dont vous ne voulez pas puis recompresser le .tgz.

C'est long et vous avez besoin d'un espace disque suffisant, mais à ma connaissance, il n'y a pas d'autre moyen de le faire.

Étant donné que vous avez déjà un chemin comme /tmpdir/withalotofspacecelui-ci qui a suffisamment d'espace libre (vérifiez-le en utilisant df -h /tmpdir/withalotofspace), vous pouvez faire quelque chose comme ceci:

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .
DavAlPi
la source
Comme le montrent les autres réponses, grâce à la tuyauterie, il n'est pas nécessaire de stocker des données non compressées sur le disque à tout moment
Tobias Kienzler
0

J'aime la réponse de @Gilles, sauf qu'elle peut être encore simplifiée. Après la décompression, par exemple, gunzip foo.tgzle fichier sera foo.taret les fichiers peuvent être supprimés avec tar -f foo.tar --delete file|directory. Voici un exemple de suppression d'un répertoire d'un fichier 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/

Des types de fichiers spécifiques peuvent être trouvés avec tar -tf foo.tar|egrep -i '.jpg$'.

Funmungus
la source