2

I’m on a Mac, El Capitan.

My zip file structure:

README.md
source/README.md

I can’t seem to --exclude the root-level README.md without also excluding the one in the source directory too.

I’ve been trying variations of things, like:

# Doesn’t exclude anything:
tar -xf master.zip --strip-components 1 --exclude=/README.md
tar -xf master.zip --strip-components 1 --exclude=/{install.sh,README.md}

# Excludes both files:
tar -xf master.zip --strip-components 1 --exclude=./README.md
tar -xf master.zip --strip-components 1 --exclude={install.sh,README.md}
tar -xf master.zip --strip-components 1 --exclude=./{install.sh,README.md}

Question:

How can I exclude only the root-level README.md

3

Actually, tar may exclude files with --anchored

patterns match file name start

But then you have to write the whole file path (which also changes with cd):

$ cd /where/source/lives
$ tar -cf master.zip --anchored --exclude={source/install.sh,README.md} -- *

If you need some flexibility, use find.
The list of files to be compressed may be created with this command,
the ! -name README.md rejects the base README.md file :

$ path="/path/to/files"
$ find "$path/" ! -path  "$path"/README.md -print

Be careful with the slashes /, they do matter. If that contains the correct list of files to compress, then just inject that to tar (add a 0 to -print and create the tar command):

find "$path/" ! -path  "$path"/README.md -print0 |
tar --no-recursion --null -T- --exclude=install.sh -v -cf master.zip

Note that tar is using the --null option to match the -print0 of find.

As find is providing all the recursion needed, use tar's --no-recursion option.

Also, the file install.sh is still being excluded in tar (which might as well have been removed with find, but that is just personal preference).

In production, remove the -v option to get a less verbose tar command.


To decompress (instead of compress as above), use this:

tar -xf master.zip --anchored --exclude={source/install.sh,README.md}

Or, if you use the second option to create the compressed file, the files excluded will not be inside master.zip and all you would need to do is:

tar -xf master.zip    
| improve this answer | |
  • +1 for paying more attention to the man page than I did and finding --anchored, but find somedir \! -name README.md will reject all files named README.md, not just the top-level one. You would need to use -path instead. – larsks Mar 27 '16 at 17:59
  • @larsks Solved -name issue. Anything else? – user79743 Mar 27 '16 at 18:28
  • 1
    This is very instructional and useful @BinaryZebra, thank you! Unfortunately, I was not able to get --anchored to work on my version of tar on Mac OS X. I did try your other suggestions … I wasn't able to get your other options to work as it seemed to compress rather than decompress. Sorry if I'm missing something obvious. :( – mhulse Mar 27 '16 at 20:18
  • 1
    @mhulse Yes, the commands are compressing. You need de-compressing? changing c to x should be easy. Let me work it out. – user79743 Mar 27 '16 at 20:49
  • 2
    @mhulse Well, to use the --anchored option you do need GNU tar. Which is very easy to install. Maybe you could try using a ^ at the beginning of the pattern with your version of bsd tar. Your choice. – user79743 Mar 27 '16 at 21:15
2

Someone may show up with a better answer, but if tar's --exclude option isn't cutting it, you can use find to generate a list of files and then feed that tar. For example:

find * -path README.md -prune -o -print | 
tar --no-recursion -cf /tmp/data.tar -T-

This prints a list of all files (and directories) that are not the top-level README.md, and then feeds them to tar, which reads its list of files from stdin (using -T-). The --no-recursion flag is necessary because otherwise tar will automatically include all files in directories, which you don't want because these files will also be produced by find and you would end up with multiple files in the archive with the same name.

A more robust version might look like:

find * -path README.md -prune -o -print0 | 
tar --no-recursion -cf /tmp/data.tar --null -T-

Here, the -print0 to find and the --null to tar mean that filenames will be separated by ASCII NUL characters rather than whitespace, which means the pipeline would handle filenames containing spaces.

| improve this answer | |
  • Thanks so much for you help! I really appreciate it! I was not able to get it to work for my particular situation as it seemed to compress master.zip rather than decompress it. I feel terrible that I might have not made my question more clear (I've updated the title to include "unzip"). Then again, I could just be doing it wrong, or missing something obvious (I apologize either way). With that said, I'm learning a ton, so not all is lost. :) – mhulse Mar 27 '16 at 20:29
1

The pax utility has an exclusion feature that's a bit broader than BSD tar. Its -s option lets you transform names as they are stored or extracted, and if a name is transformed to an empty string, that file is excluded.

(BSD tar has a somewhat similar -s option, but going by the documentation, it doesn't seem to have the exclusion-on-empty feature.)

zcat foo.tar.gz | pax -r -pe -s'!^README\.md$!!' -s'!^\./README\.md$!!'

Note that I'm assuming a (possibly compressed) tar file. If you have a zip file, use unzip instead.

unzip foo.zip -x 'README.md'
| improve this answer | |
  • Thank you for your help! I finally have time to get back to testing things tonight, I'll let you know how it goes! +1 – mhulse Mar 29 '16 at 16:22

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.