I am trying to figure out how to create a zip file for each subfolder containing only files that match my criteria.

For instance I have:


Each folder contains the same set of files but the filenames in each are slightly different, but the extensions are always the same. I would like to zip the .shp, .shx, .qpj, .prj and .dbf in each folder. Each folder would be its own zip file. I would rather not store the actual folder name other than as the name of the zip file.

I have tried:

find . -type d | xargs -I {} zip -r {}.zip {}

This creates each zip file but would zip every file not just the ones with the extensions I would like, it also stores the folder name in the zip.

find . -type d | xargs -I {} zip -r {}.zip {}'/'*.shp {}'/'*.shx {}'/'*.dbf {}'/'*.prj {}'/'*.qpj 

The above does nothing other than gives errors that there is nothing to do.

Hopefully my poor attempts give a better idea of what I'm trying to do.

Any help appreciated.

  • You could try a programmatic approach using for example Python's zipfile. – Faheem Mitha Oct 28 '13 at 21:13
  • Welcome to unix.stackexchange.com, for better contribution, please read how to question and how to answer, by the way rename user159965 to your nickname. – PersianGulf Oct 28 '13 at 21:39

If all the weirdness in your directory names is that they have spaces, this should do:

shopt -s nullglob
for dir in */;do
    zip "$dir".zip "$dir"/*.{shp,shx,qpj,prj,dbf}
  • IF I run this from Terminal it doesn't work, it looks like it splits the find when a space is found. For instance one folder is called "The Saddle". I get an error saying "zip error: Nothing to do! (./The.zip)" and another "zip error: Nothing to do! (Saddle.zip)" There are other errors in between saying "zip warning: name not matched: Saddle/*.sh" and repeated for each file extension. – Steven Oct 29 '13 at 19:47
  • @Steven Answer updated. This will conserve spaces but will not do recursion. It will work on directories at the current level only. – Joseph R. Oct 29 '13 at 19:54
  • That's almost it, except the zip file it created inside each folder which is actually better for my purposes but it missed adding a name for each zip. The filename for each zip is set to ".zip" it hasn't put the folder name before ".zip", it has created 2 folders inside of the zip file itself. Hope that makes sense. – Steven Oct 29 '13 at 20:22
  • @Steven My bad. Should be working now... – Joseph R. Oct 29 '13 at 20:24
  • Thank you so much that works. I have added: 'mv "$dir".zip "$dir"' just before the done command to move the zip file into the folder the files were zipped from. – Steven Oct 29 '13 at 20:46

Well, not sure if with one liner is possible, probably yes. But I did what you need instead with this:

find . -type d -maxdepth 1 | while read -r i; do
    find $i -name "*.shp" -o -name "*.shx" -o -name "*.shx" -o -name "*.prj" -o -name "*.qpj" |zip -@ "$i".zip

Each zip file will be your dir name.

  • I forgot to mention some of my folder names have spaces. This zips only the folders without spaces in the name. I'm almost there thanks. – Steven Oct 28 '13 at 21:30
  • Updated the question. This should work but if a directory does not have any match for the filesnames it will throw a error / info stating "nothing to do", so no zip file will be created anyway. – BitsOfNix Oct 28 '13 at 23:06
  • This is probably a stupid question but should I run this as a script. For example save it as a .sh file and run it with "bash filename.sh" I get an error if I do that. If I just run it from Terminal it doesn't run correctly due to being split across lines. – Steven Oct 29 '13 at 19:39
  • To give a better idea of the folder structure and filenames, here's a screenshot of an example of the folders on the left and the contents of one of the folders on the right. You can also see the zip files the above command created. It missed a few folders. !screenshot – Steven Oct 29 '13 at 20:02

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.