How can I make a zip of all the files and subdirectories in the directory mydir, except all those files/dirs that begin with a .*?

The command:

zip -r mydir.zip mydir/

...will include everything. For example, if I have:


I'd like foo and bar to be included in mydir, but not .hello.

How can I do this?


7 Answers 7


This works for me:

zip -r mydir.zip mydir -x "*/.*"

@Joe Internet, @Dariusz: normal shell patterns won't work properly because zip matches against the full path+filename internally (as the zip manual explains... ;) )

  • 1
    Claeys - My example workerd for me, but to be fair, I used Ch Shell (includes zip) under Win7. I CDed into my test directory, and used 'zip -r test.zip ./ -x .*.*' (minus the single quotes). If I use 'zip -r mydir.zip mydir -x "/."' (minus the single quotes), it doesn't exclude the hidden file in my test directory. I guess it's down to differences in the shells used to test with. Commented Aug 22, 2010 at 19:01
  • Sorry, did not work for me on macOS. But the answer below worked. Commented Nov 16, 2022 at 21:32

Shorter, and takes advantage of the features of globbing:

zip -r mydir.zip mydir/*

(. files are not included in the * wildcard)

Note that the directory 'mydir/' may not be included in the paths of the files in the resultant zip file, so this will change the output slightly. You may have to change your extraction process as a result.

  • Interesting thing I just found: It will add a top-level hidden folder, but none of its contents (hidden or visible)
    – Anthony
    Commented Nov 7, 2020 at 9:00
  • Thank you, worked for me on macOS Commented Nov 16, 2022 at 21:33

The following approach works for this type of directory tree:

$ tree .
├── adir1
│   ├── afile1
│   ├── afile2
│   ├── afile3
│   └── afile4.txt
├── adir2
│   ├── afile1
│   ├── afile2
│   ├── afile3
│   └── afile4.txt
├── adir3
│   ├── afile1
│   ├── afile2
│   ├── afile3
│   └── afile4.txt
├── afile1
├── afile2
├── afile3
├── foo.test

This was the solution that worked for this scenario (which I believe is the more general case).

 $ find . -type f -not -path '*/\.*' -exec zip -r test.zip {} +


$ find . -type f -not -path '*/\.*' -exec zip -r test.zip {} +
updating: adir1/afile1 (stored 0%)
updating: adir1/afile1.zip (stored 0%)
updating: adir1/afile2 (stored 0%)
updating: adir1/afile3 (stored 0%)
updating: adir1/afile4.txt (stored 0%)
updating: adir2/afile1 (stored 0%)
updating: adir2/afile2 (stored 0%)
updating: adir2/afile3 (stored 0%)
updating: adir2/afile4.txt (stored 0%)
updating: adir3/afile1 (stored 0%)
updating: adir3/afile2 (stored 0%)
updating: adir3/afile3 (stored 0%)
updating: adir3/afile4.txt (stored 0%)
updating: afile1 (stored 0%)
updating: afile2 (stored 0%)
updating: afile3 (stored 0%)
updating: foo.test (deflated 87%)

If you prefer more complex filtering capabilities, find is a good tool:

find mydir/ -! -name ".hello" -print | zip mydir -@

Have fun with 'find'.


You can use shell patterns to exclude matches, all is written in zip manual (with examples)


Try this...

zip -r mydir.zip mydir/ -x .*.*

On a UNIX system this will prevent shell globbing and let zip handle the pattern itself:

zip -r mydir.zip mydir/ -x '*/.*'
  • Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Apr 3, 2023 at 23:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .