72

I'm making a shell script to package some files. I'm zipping a directory like this:

zip -r /Users/me/development/something/out.zip /Users/me/development/something/folder/

The problem is that the resultant out.zip archive has the entire file path in it. That is, when unzipped, it will have the whole "/Users/me/development/anotherthing/" path in it. Is it possible to avoid these deep paths when putting a directory into an archive?

When I run zip from inside the target directory, I don't have this problem.

zip -r out.zip ./folder/

In this case, I don't get all the junk. However, the script in question will be called from wherever.

FWIW, I'm using bash on Mac OS X 10.6.

quack quixote
  • 43,504
jerwood
  • 1,527

6 Answers6

124

Your script should use cd or pushd and popd to move into the directory that will be the root of the archive before issuing the zip command. How you do this exactly will depend on how the script knows what to zip up. But, if you want /Users/me/development/something/folder zipped with internal paths of just ./folder, you'd need to do this:

pushd /Users/me/development/something
zip -r /path/to/out.zip ./folder/
popd

That will result in your out.zip containing the relative paths you want.

If you need assistance with scripting that, you'll need to show us your script.

quack quixote
  • 43,504
13

The problem is that the resultant out.zip archive has the entire file path in it.
...
Is it possible to avoid these deep paths when putting a directory into an archive?

Yes. Use the -j option with zip. -j is "junk the path". According to the man page on zip:

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).

Using -j means the following command:

zip -j myarchive.zip file1.txt dir1/file2.txt dir2/dir3/file3.txt ../file4.txt

Will create an archive that looks like:

myarchive.zip
    |
    +-- file1.txt
    +-- file2.txt
    +-- file3.txt
    +-- file4.txt
jww
  • 12,722
10

There is pushd and popd and $OLDPWD. Assuming the $PWD is /Users/me/development do:

pushd something/folder
zip -r $OLDPWD/something/out.zip *
popd

Now the $PWD is back to /Users/me/development

IOzc
  • 201
2

Zip without including paths, but include parent directory, and without having to hardcode its name

A slightly improved version of @quack's accepted answer.

If you are doing this in a script and don't want to have to hardcode the parent directory, you can do this:

pushd /Users/me/development/something/folder/;
zip -r ../out.zip ../$(basename $PWD)
popd;

The ../$(basename $PWD) will ensure that the files are retained in the parent directory when extracted.

So now unzip my.zip will give a folder containing all your files:

folder
├── file1
├── file2
├── dir1
│   ├── file3
│   ├── file4

Instead of littering the current directory with the unzipped files:

file1
file2
dir1
├── file3
├── file4
AndrewD
  • 512
0

I think this is the most compact version and the one that works best.

OLDPWD=$PWD; env -C /path/to/directory zip -r "$OLDPWD/directory.zip" .

This will make a zip file in the current directory named "directory.zip". Inside of the zip file the there will be the contents of /path/to/directory in the same exact file structure.

Flafy
  • 119
0

If you want the contents of a folder zipped up into an archive in your current directory it's simply

env -C 'path/to/directory' zip -r "$PWD/name.zip" .

If you want that folder to exist in the root of the zip instead

env -C 'path/to' zip -r "$PWD/name.zip" directory

So for your exact example:

env -C '/Users/me/development/something' \
    zip -r '/Users/me/development/something/out.zip' folder
Hashbrown
  • 3,338
  • 4
  • 39
  • 51