Tar: how can I exclude intermediate directories but include leaf directories

findtar

I want to create a tar file suitable for extracting into /. I've created a work directory that represents the root of the file system, and it has all the stuff I want included in the tar underneath, like: etc/rc.d/init.d/glassfish3, opt/glassfish3/..., and other directories and files under opt/....

When I do tar zcvpf files.tgz * it includes the intermediate directories (like etc, etc/rc.d, and opt) in the tar file. Then when I extract it into / on another system, it has the undesirable behavior of mucking with ownership and permissions on those directories. I really want to leave those alone and not touch them.

So I thought I found a good way around this with:

find . -type f -print0 | tar zcvpf files.tgz --null --files-from -

which creates a tar that only includes files. This is great, it only gets the files I put in there… except I just discovered it's not picking up important leaf directories, like:

opt/glassfish3/glassfish/lib/asadmin

which is an empty directory (and needed by Glassfish3, or it will complain).

How can I create a tar file that skips intermediates but not final directories? I have a feeling some find+awk magic might do it. It doesn't need to be a one-liner though, readability is important. Thanks.


Edit: I found this. Other/better ideas welcome:

cat <(find . -type f -print0) <(find . -type d -empty -print0) | tar zcvpf files.tgz --null --files-from -

Best Answer

find can take -o for "or", so you can combine your two find commands like so:

find . \( -type f -o -type d -empty \) -print0 | tar ...

Or, if you can guarantee all the files can fit on one command line,

find . \( -type f -o -type d -empty \) -exec tar cvfz files.tgz {} +
Related Question