Elimine eficientemente los archivos de grandes .tgz

14

Suponga que tengo un gzip comprimido tar-ball compressedArchive.tgz (+100 archivos, totalizando + 5gb).

¿Cuál sería la forma más rápida de eliminar todas las entradas que coincidan con un patrón de nombre de archivo dado, por ejemplo, el prefijo * .jpg y luego almacenar los restos en un gzip: ed tar-ball nuevamente?

Reemplazar el archivo antiguo o crear uno nuevo no es importante, lo que sea más rápido.

Aksel Willgert
fuente

Respuestas:

14

Con GNU tar, puedes hacer:

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

( pigzsiendo la versión multiproceso de gzip).

Puede sobrescribir el archivo sobre sí mismo como:

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

Pero eso es bastante arriesgado, especialmente si el resultado termina siendo menos comprimido que el archivo original (en cuyo caso, el segundo pigzpuede terminar sobrescribiendo áreas del archivo que el primero aún no ha leído).

Stéphane Chazelas
fuente
Gracias por la respuesta, votada. ejecutará benchmark la próxima semana para ver cuál funciona mejor para mi archivo y sistema y aceptarlo.
Aksel Willgert
8

No descarte la manera fácil: puede ser lo suficientemente rápido para su propósito. Con avfs para acceder al archivo como directorio:

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 herramientas más primitivas, primero extraiga los archivos excluyendo los .jpgarchivos, luego cree un nuevo archivo.

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 su alquitrán tiene --exclude:

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

Sin embargo, esto puede alterar la propiedad y los modos del archivo si no lo ejecuta como root. Para obtener mejores resultados, use un directorio temporal en un sistema de archivos rápido: tmpfs si tiene uno que sea lo suficientemente grande.

El soporte para que los archivadores actúen como una transferencia (es decir, leer un archivo y escribir un archivo) tiende a ser limitado. GNU tar puede eliminar miembros de un archivo con la --deleteopción de operación ( “La --deleteopción se ha informado que funcionan correctamente cuando se taractúa como un filtro de stdina stdout.”), Y eso es probablemente su mejor opción.

Puede crear potentes filtros de archivo en unas pocas líneas de Python. Su tarfilebiblioteca puede leer y escribir desde secuencias no buscables, y puede usar código arbitrario en Python para filtrar, renombrar, modificar ...

#!/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- deja de ser malvado'
fuente
También destrozaría uid / usernames si se ejecuta como root a menos que se realice en una máquina que tenga la misma asignación de nombre de usuario uid <=> que aquella en la que se creó inicialmente el archivo tar. Las ACL, los atributos extendidos también pueden verse afectados. Con tar, es posible que desee agregar la popción.
Stéphane Chazelas
2

Con el tar que viene en Mac OSX, puede hacer esto:

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

Para hacer esto, probablemente deba extraer todo el contenido del archivo .tgz en un directorio local, luego borrar los archivos que no desea y luego volver a comprimir el .tgz.

Es largo y necesita suficiente espacio libre en el disco, pero que yo sepa, no hay otra manera de hacerlo.

Dado que ya tiene alguna ruta como /tmpdir/withalotofspaceesa, tiene suficiente espacio libre (verifíquela usando df -h /tmpdir/withalotofspace), puede hacer algo como esto:

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .
DavAlPi
fuente
Como muestran las otras respuestas, a través de las tuberías no hay necesidad de almacenar datos sin comprimir en el disco en ningún momento
Tobias Kienzler
0

Me gusta la respuesta de @Gilles, excepto que se puede simplificar aún más. Después de descomprimir, por ejemplo, gunzip foo.tgzel archivo será foo.tary los archivos se pueden eliminar con tar -f foo.tar --delete file|directory. A continuación se muestra un ejemplo de eliminación de un directorio de un archivo 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/

Se pueden encontrar tipos de archivos específicos con tar -tf foo.tar|egrep -i '.jpg$'.

Funmungus
fuente