104

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
  • 72,471
Dami
  • 1,191

7 Answers7

87

Hope this helps.

(cd directory_to_zip && 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
  • 987
69

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
  • 72,471
robrtsql
  • 871
  • This appears to be the correct answer. – Dr. Chocolate Feb 24 '19 at 17:48
  • 36
    What about nested paths/folders though? – GuyPaddock Mar 13 '19 at 00:25
  • 48
    This will omit all folders in the archive, and if you have duplicate file names in different folders, this will blow up. This has its place, but only if you don't care about folders and just want files. Not what the OP was asking for, but still good knowledge – Govind Rai Apr 03 '19 at 23:26
  • ubuntu 20 bash : zip error: Invalid command arguments (cannot repeat names in zip file) – JRichardsz Nov 11 '22 at 19:40
  • 1
    Following up on @GuyPaddock's question, how do you junk the parent folder path but not the nested folders, is cd path && zip... the only way? – Lance Pollard Feb 22 '24 at 05:34
  • 1
    Govind Rai said it more diplomatically than I would have -- this is an incorrect answer as the original question specified a need to retain the subdirectories. – Lucas Ross May 10 '24 at 16:55
42

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
  • 588
  • 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
  • 59
    zip -r test.zip test/* from the outside adds test as directory into the zip file – smihael May 03 '17 at 20:41
  • 13
    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
  • 2
    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
  • 2
    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
32

How about this command?

$ cd somedir ; zip -r ../zipped.zip . * ; cd ..
Alfred
  • 429
  • 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
9
(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.

7
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
  • 171
4

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,894