76

I have a single directory that contains dozens of directories inside of it.

I'm new to command line and I'm struggling to come up with a command that will zip each sub-directory into a unique sub-directory.zip file.

So in the end my primary directory will be filled with all of my original sub-directories, plus the corresponding .zip files that contain the zipped up content of each sub-directory.

Is something like this possible? If so, please show me how it's done.

0

2 Answers 2

137

You can use this loop in bash:

for i in */; do zip -r "${i%/}.zip" "$i"; done

i is the name of the loop variable. */ means every subdirectory of the current directory, and will include a trailing slash in those names. Make sure you cd to the right place before executing this. "$i" simply names that directory, including trailing slash. The quotation marks ensure that whitespace in the directory name won't cause trouble. ${i%/} is like $i but with the trailing slash removed, so you can use that to construct the name of the zip file.

If you want to see how this works, include an echo before the zip and you will see the commands printed instead of executed.

Parallel execution

To run them in parallel you can use &:

for i in */; do zip -0 -r "${i%/}.zip" "$i" & done; wait

We use wait to tell the shell to wait for all background tasks to finish before exiting.

Beware that if you have too many folders in your current directory, then you may overwhelm your computer as this code does not limit the number of parallel tasks.

9
  • Thanks this looks great! However one potential problem I thought of: will this zip ALL directories within each sub-directory into separate files? I only want to zip the 1st-level subdirectories as single compressed files. I don't want to create additional zip files for 2nd-level, 3rd-level sub-directories, etc... Please let me know if that makes sense. Thanks again!
    – Evster
    Mar 19, 2013 at 21:44
  • Only the first level ones like you requested. Mar 19, 2013 at 21:49
  • 1
    The */ names every direct subdirectory, not every descendant directory. So you'll only get zips for the uppermost level, just the way you want them. The version with echo in it would have demonstrated that aspect. Zipping every nested directory into its own file would in fact be more work, and probably best solved using find -type d among other tricks.
    – MvG
    Mar 19, 2013 at 21:53
  • 2
    @fritzmg: A local test on my Linux suggests that yes, files starting in a dot are included. This would be a property of the Info-ZIP tool, not of the command I gave, so depending on what your zip binary is you might get different behavior. In order to also create zip files for top level directories (i.e. children of current directory) starting with a dot, you could use shopt -s dotglob to make glob patterns match hidden files as well.
    – MvG
    Aug 13, 2018 at 17:24
  • 8
    To create a zip which doesn't have the parent directory as its root: for i in */; do (cd "$i"; zip -r "../${i%/}.zip" .); done
    – chris
    Sep 6, 2018 at 12:51
0

If you want to do this on Windows / Batch, here is a similar script I put together.

@ECHO OFF
REM Cycle Through all of the directories in the current folder
for /D %%d in (*) do (
    REM Change to the directory
    pushd %%d
    REM Make the destination directory.
    mkdir "Z:\%%d"

    REM Cycle Through all Subdirectories
    for /D %%b in (*) do (
        REM Zip up all subdirectores, and put it in the destination.
        7z -r a "Z:\%%d\%%b.zip" %%b
    )
    popd
)

You must log in to answer this question.

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