# Tar up all PDFs in a directory, retaining directory structure

I'm trying to create a compressed tarball that contains all PDF files that exist in one of my directories. The directory structure needs to be retained. Empty directories are not needed, but I really don't care if they're there.

For example, say I had a directory that looked like this:

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


After running the command, I'd like to have dir.tar.gz contain this:

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


Possible?

-

This will list all the PDFs:

$find dir/ -name '*.pdf' ./dir/subdir2/subsubdir1/document.pdf ./dir/subdir3/another-document.pdf  You can pipe that to xargs to get it as a single space-delimited line, and feed that to tar to create the archive: $ find dir/ -name '*.pdf' | xargs tar czf dir.tar.gz


(This way omits the empty directories)

-
That's so awesome, thanks for the help. Here's what I came up with: find docs $$-iname '*.pdf' -o -iname '*.mp3'$$ -printf '"%p"\n' | xargs tar czf docs-media.tar.gz –  Matt Alexander Jan 10 '11 at 20:26
@mattalexx: Beware that this command will not work if any of the file names contain spaces or \'" (xargs's fault), and will not work if there are too many file names (the kernel's fault). –  Gilles Jan 10 '11 at 20:29
@Gilles Regarding filenames with spaces and single quotes, the -printf '"%p"\n' part takes care of that (at least it did for me). –  Matt Alexander Jan 10 '11 at 20:31
@Gilles Interesting about the kernel restriction. How many arguments can you have in a command in Linux? –  Matt Alexander Jan 10 '11 at 20:32
Oh, on the “will not work”, note that the failure mode here is that if the command line is too long, xargs will split it up, so that the last tar invocation will silently overwrite files written by previous invocations. –  Gilles Jan 10 '11 at 20:46

With bash ≥4 or zsh and GNU tar:

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


This might not work if you have a very large number of PDF files and the command line is too long. Then you would need a more complex find-based solution (again, using GNU tar):

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


Alternatively (and portably) you can create the archive with pax.

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


The first -s says to include all .pdf files, without changing their name. The second -s says to rename all other files to an empty name, which actually means not to include them in the archive.

-
Oh yeah, I meant to mention zsh's **; I didn't even realize bash 4 had that now –  Michael Mrozek Jan 10 '11 at 20:34