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:


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




This will list all the PDFs:

$ find dir/ -name '*.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)

  • 1
    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
  • 3
    @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
  • 2
    @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
  • 1
    @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
  • 5
    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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.