88

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?

7 Answers 7

73

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.

6
  • 2
    I wanted to add this as a comment to @Alfred UC's answer but I don't have enough reputation for that.
    – YesYouKen
    Jun 22, 2019 at 9:21
  • 3
    If it actually solves the problem, then it may be a solution. Jun 22, 2019 at 10:56
  • 1
    This is better as an answer. Does this work in both bash and sh? Sep 29, 2019 at 20:32
  • 4
    hands down the most elegant one.
    – kakyoism
    Jun 17, 2021 at 12:37
  • 1
    Also, other solutions such as using wildcard character * become problematic when dealing with very large number of files in the folder (throws "argument list too long" error). This solution doesn't present that problem Aug 7, 2023 at 6:23
64

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).
5
  • This appears to be the correct answer. Feb 24, 2019 at 17:48
  • 25
    What about nested paths/folders though?
    – GuyPaddock
    Mar 13, 2019 at 0:25
  • 38
    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 3, 2019 at 23:26
  • ubuntu 20 bash : zip error: Invalid command arguments (cannot repeat names in zip file)
    – JRichardsz
    Nov 11, 2022 at 19:40
  • 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
    Feb 22 at 5:34
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;
12
  • 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 7, 2014 at 2: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 7, 2014 at 2:19
  • 57
    zip -r test.zip test/* from the outside adds test as directory into the zip file
    – smihael
    May 3, 2017 at 20:41
  • 11
    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 7, 2017 at 18:56
  • 1
    For those who want to also archive dot files, zip -r filename.zip ./* will not work, please use zip -r filename.zip . instead. Apr 19, 2019 at 8:10
31

How about this command?

$ cd somedir ; zip -r ../zipped.zip . * ; cd ..
3
  • 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, 2016 at 8: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, 2016 at 16:07
  • Only thing what worked for me,
    – progonkpa
    Dec 9, 2021 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)

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.

2
  • what does the extra - do? Feb 27, 2023 at 10:22
  • 1
    @JosephAstrahan I believe it prints the result to stdout. Feb 27, 2023 at 12:32
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" ./*)

You must log in to answer this question.

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