Guarda todos los archivos PDF en un directorio, conservando la estructura del directorio

11

Estoy tratando de crear un tarball comprimido que contenga todos los archivos PDF que existen en uno de mis directorios. La estructura del directorio necesita ser retenida. No se necesitan directorios vacíos, pero realmente no me importa si están allí.

Por ejemplo, supongamos que tenía un directorio que se veía así:

dir
dir/subdir1
dir/subdir1/subsubdir1/song.mp3
dir/subdir2
dir/subdir2/subsubdir1
dir/subdir2/subsubdir1/document.pdf
dir/subdir2/subsubdir1/another-song.mp3
dir/subdir2/subsubdir1/top-ten-movies.txt
dir/subdir3
dir/subdir3/another-document.pdf

Después de ejecutar el comando, me gustaría que dir.tar.gzcontenga esto:

dir
dir/subdir2
dir/subdir2/subsubdir1
dir/subdir2/subsubdir1/document.pdf
dir/subdir3
dir/subdir3/another-document.pdf

¿Posible?

Matt Alexander
fuente

Respuestas:

10

Esto enumerará todos los archivos PDF:

$ find dir/ -name '*.pdf'
./dir/subdir2/subsubdir1/document.pdf
./dir/subdir3/another-document.pdf

Puede canalizar eso para xargsobtenerlo como una sola línea delimitada por espacios y alimentarlo tarpara crear el archivo:

$ find dir/ -name '*.pdf' | xargs tar czf dir.tar.gz

(De esta manera se omiten los directorios vacíos)

Michael Mrozek
fuente
1
Eso es genial, gracias por la ayuda. Esto es lo que se me ocurrió:find docs \( -iname '*.pdf' -o -iname '*.mp3' \) -printf '"%p"\n' | xargs tar czf docs-media.tar.gz
Matt Alexander
3
@mattalexx: tenga en cuenta que este comando no funcionará si alguno de los nombres de archivo contiene espacios o \'"(error de xargs), y no funcionará si hay demasiados nombres de archivo (error del núcleo).
Gilles 'SO- deja de ser malvado'
2
@Gilles Con respecto a los nombres de archivo con espacios y comillas simples, la -printf '"%p"\n'parte se encarga de eso (al menos lo hizo por mí).
Matt Alexander
1
@Gilles Interesante sobre la restricción del kernel. ¿Cuántos argumentos puedes tener en un comando en Linux?
Matt Alexander
55
Ah, en "no funcionará", tenga en cuenta que el modo de falla aquí es que si la línea de comando es demasiado larga, xargs la dividirá, de modo que la última invocación de tar sobrescribirá silenciosamente los archivos escritos por invocaciones anteriores .
Gilles 'SO- deja de ser malvado'
6

Con bash ≥4 o zsh y GNU tar:

tar -czf dir.tar.gz dir/**/*.pdf

Esto podría no funcionar si tiene una gran cantidad de archivos PDF y la línea de comando es demasiado larga. Entonces necesitaría una solución basada en hallazgos más compleja (nuevamente, usando GNU tar):

tar -cf dir.tar -T /dev/null
find dir -name '*.pdf' -exec tar -rf dir.tar {} +
gzip dir.tar

Alternativamente (y de forma portátil) puede crear el archivo con pax .

pax -w -x ustar -s '/\.pdf$/&/' -s '/.*//' . | gzip >dir.tar.gz

El primero -sdice que incluya todos los .pdfarchivos, sin cambiar su nombre. El segundo -sdice cambiar el nombre de todos los demás archivos a un nombre vacío, lo que en realidad significa no incluirlos en el archivo.

Gilles 'SO- deja de ser malvado'
fuente
Oh sí, quise mencionar zsh's **; Ni siquiera me di cuenta de que bash 4 tenía eso ahora
Michael Mrozek