83

I want to zip many folders in a directory tree like so

V-
 something.txt
 folder
 folder
 g.jpg
 h.jar

When I try to zip it, it ends creating a zip archive with the v folder instead of the contents of it (the sub directories and files)

How can I avoid this?

Zanna
  • 69,223
  • 56
  • 216
  • 327
Dami
  • 981
  • 1
  • 6
  • 10

7 Answers7

68

Hope this helps.

(cd directory && zip -r ../out.zip .)

It keeps the main shell in the same directory and only changing the directory of the sub-shell which dies after the command.

YesYouKen
  • 781
  • 5
  • 3
63

Use the -j or --junk-paths option in your zip command.

From the zip man page:

-j

--junk-paths

Store just the name of a saved file (junk the path), and do not store directory 
names. By default, zip will store the full path (relative to the current 
directory).
Zanna
  • 69,223
  • 56
  • 216
  • 327
robrtsql
  • 787
  • 5
  • 3
41

So if I understand correctly, you are trying to archive the files & folders in a particular folder but without including the root folder.

Example:

/test/test.txt
/test/test2.txt

where test.txt and test2.txt would be stored in the zip, but not /test/

You could cd into the /test/ directory then run something like,

zip -r filename.zip ./*

Which would create an archive in the same folder named filename.zip. Or if running it from outside the folder you could run,

zip -r test.zip test/*

The /* is the part that includes only the contents of the folder, instead of the entire folder.

Edit: OP wanted multiple zips, solution ended up being a bit of a hack, I am curious as to whether there is a better way of doing this.

for d in */ ; do base=$(basename "$d") ; cd $base ; zip -r $base * ; mv "${base}.zip" .. ; cd .. ; done;
jspaetzel
  • 570
  • 5
  • 5
  • yes but i have a lot of file which i do the same thing on so it would tedious do it like that so is there like a bash script or something that would automate the same process on the directory that has all the folders – Dami Sep 07 '14 at 01:42
  • Oh, something like this then? (this would create archives of each folder within the current folder) `for d in */ ; do base=$(basename "$d") ; zip -r "${base}.zip" "$d" ; done;` – jspaetzel Sep 07 '14 at 02:01
  • 4
    Ok I ran the script and it created a the parent directory in the archive i want only the contents of the folder to be in the archive – Dami Sep 07 '14 at 02:13
  • 1
    my mistake, missed a bit of it. added a -j parameter which i just looked up, apparently skips the part you don't want. try this: `for d in */ ; do base=$(basename "$d") ; zip -rj "${base}.zip" "$d" ; done;` – jspaetzel Sep 07 '14 at 02:19
  • Ok so i think the -j deflates all the folders in the archive so i have subfolders in the folder i want to archive to it deflates them also an them put them in the root of the archive – Dami Sep 07 '14 at 02:23
  • This is a bit of a hack and i feel like there should be a better way to do it... but i think this might do the trick. `for d in */ ; do base=$(basename "$d") ; cd $base ; zip -r $base * ; mv "${base}.zip" .. ; cd .. ; done;` – jspaetzel Sep 07 '14 at 02:45
  • Thanks Dude The Hack Worked Now I can Continue With My Work – Dami Sep 07 '14 at 02:55
  • 54
    zip -r test.zip test/* from the outside adds test as directory into the zip file – smihael May 03 '17 at 20:41
  • 9
    as @smihael stated, `zip -r test.zip test/*` does not work. is there any correct way to achieve this from outside the directory? – andrhamm Aug 07 '17 at 18:56
  • For those who want to also archive dot files, `zip -r filename.zip ./*` will not work, please use `zip -r filename.zip .` instead. – Weihang Jian Apr 19 '19 at 08:10
  • 1
    This answer is wrong, unfortunately. Includes the parent directory, at least for Info-ZIP on mac os. – Ilia Sidorenko Apr 30 '21 at 02:10
  • 1
    Doesn't work. @smihael pointed the issue out correctly. – progonkpa Dec 09 '21 at 14:09
31

How about this command?

$ cd somedir ; zip -r ../zipped.zip . * ; cd ..
Alfred
  • 419
  • 4
  • 6
  • 6
    While this is a correct answer, the introduction doesn't sound like you're convinced yourself. It would also help to explain a little bit, what the command does. – Nephente Mar 11 '16 at 08:14
  • 2
    This was my solution too, but I dislike it because it involves `cd`. Was hoping there was a way to specify the stored path more precisely. – nilskp Oct 14 '16 at 16:07
  • Only thing what worked for me, – progonkpa Dec 09 '21 at 14:09
6
cd `dirname path/to/archive` && zip -rq $OLDPWD/arhive.zip . && cd -

This works not only with flatten tree (like -j) and you can specify any dir (not only children)

Glech
  • 161
  • 1
  • 1
4
(cd MyDirectory && zip -r - .) >MyArchive.zip

This lets you specify the resulting filename relative to the current directory, rather than relative to the target directory.

As a bonus, this overwrites the archive instead of adding new files to it, which was desired in my case.

Instead of . you can specify files/directories relative to the target directory that you want to include.

Unlike -j it preserves paths relative to the target directory, rather than flattening all files into a single directory.

HolyBlackCat
  • 713
  • 6
  • 15
3

The other answers did not satisfy me, because they either included the whole directory structure in the zip, or included an ugly ../../../../file.zip path in the zip command.

The approach below uses a common piece of boilerplate code to get the current directory (the directory in which this script is located) as an absolute path.

#!/bin/bash
dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
(cd "path/to/some/deep/directory/" && zip -r "${dir}/file.zip" ./*)
zx485
  • 2,249
  • 11
  • 24
  • 34