Say I want to add the file file.txt to foo.zip, I could just do zip -u foo.zip file.txt.

However inside the zip-file there already exist a folder with the path foo.zip/very/many/paths/ (relatively to the zip-file).

How would I add file.txt to the zip-file so it's location inside the zip-file would be foo.zip/very/many/paths/file.txt?

I could create the directory structure needed first, but isn't there an easier way?

I would normally do it like this:

$ ls
$ mkdir very
$ mkdir very/many
$ mkdir very/many/paths
$ cp file.txt very/many/paths
$ zip -u foo.zip very/many/paths/file.txt
$ rm -rf very
  • 8
    I don't know if this can be done any easier but at least you can shorten multiple mkdir commands with mkdir -p very/many/paths which creates any parent directories as needed. ;)
    – speakr
    Commented Jan 16, 2013 at 21:50
  • If you have to do it often, just create a bash script that automatise it. Taking arguments your archive and the path and file in the archive like updatezip very/many/path/file.txt file.txt
    – Depado
    Commented Jan 21, 2013 at 16:01
  • 1
    7z has an option for this 7z a yourfile.7z -sivery/many/paths/file.txt < file.txt but unfortunately, when I try this with zip, it results in an error. So this feature only works with 7z not with zip/tar :( Commented Jan 29, 2013 at 21:33
  • Possible duplicate of Add a file to a different path (but the question hasn't received an upvoted or accepted answer).
    – lgeorget
    Commented May 4, 2013 at 17:21

3 Answers 3


Use Python's zipfile library?

~/wrk/tmp$ ls test.zip
ls: cannot access test.zip: No such file or directory

Ok. There is no 'test.zip' right now...

~/wrk/tmp$ python -c 'import zipfile,sys ; zipfile.ZipFile(sys.argv[1],"a").write(sys.a
rgv[2],sys.argv[3])' test.zip /etc/motd text/motd

Let's add '/etc/motd' as 'text/motd' to the nonexisting zipfile...

~/wrk/tmp$ ls -l test.zip 
-rw-r--r-- 1 yeti yeti 473 Mar 23 09:51 test.zip

The zipfile library was nice enough to create 'test.zip'.

~/wrk/tmp$ unzip -lv test.zip 
Archive:  test.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
     357  Stored      357   0% 2014-03-20 15:47 ff1b8b7f  text/motd
--------          -------  ---                            -------
     357              357   0%                            1 file

..and it seems to contain what I wated...

Let's check it by unzipping it to stdout...

~/wrk/tmp$ unzip -p test.zip text/motd
Linux aurora 3.2.0-0.bpo.4-amd64 #1 SMP Debian 3.2.54-2~bpo60+1 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.


Now we add a 2nd file...

~/wrk/tmp$ python -c 'import zipfile,sys ; zipfile.ZipFile(sys.argv[1],"a").write(sys.argv[2],sys.argv[3])' test.zip /etc/issue otherdir/issue
~/wrk/tmp$ ls -l test.zip 
-rw-r--r-- 1 yeti yeti 605 Mar 23 09:52 test.zip
(yeti@aurora:1)~/wrk/tmp$ unzip -lv test.zip 
Archive:  test.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
     357  Stored      357   0% 2014-03-20 15:47 ff1b8b7f  text/motd
      28  Stored       28   0% 2012-09-21 22:52 f9c3990c  otherdir/issue
--------          -------  ---                            -------
     385              385   0%                            2 files
~/wrk/tmp$ unzip -p test.zip otherdir/issue                                            Debian GNU/Linux 6.0 \n \l

~/wrk/tmp$ _

One way I would suggest is by unzipping, moving the file, and then re-compressing.

As an example, let's say we have this zip file:

Archive:  foo.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2013-01-30 14:38   very/
        0  2013-01-30 14:38   very/many/
        0  2013-01-30 14:38   very/many/paths/
        0  2013-01-30 14:38   very/many/paths/foo.txt
        0  2013-01-30 14:38   file.txt
---------                     -------
        0                     5 files

To unpack the file, let's create a directory in /tmp first. Then we will perform the following actions:

  1. Unzip foo.zip to our temporary directory
    d=$(mktemp -t -d foo.zip.XXXXXX) && unzip -d $d foo.zip
  2. Move the file to it's new path (relative to temp dir $d)
    mv ${d}/file.txt ${d}/very/many/paths/
  3. In subshell: cd to temp dir & Recompress everything into a new zip file
    ( cd $d && zip -r foo.zip ./* )
  4. Move the new zip file from temp dir to replace the old one
    mv ${d}/foo.zip ./
  5. Cleanup :-)
    rm -rf ${d}
  • True, but inefficient, zip is not a solid compression format and allows adding and removing contents without recompression. However, if adding files and even entire dir structure to a zip file happens frequently, something could be done differently.
    – orion
    Commented Mar 10, 2014 at 19:06
  • It is well known that the .zip format is nowhere near the highest compression ratio out there. There are much better choices such as 7z nowadays. However, the .zip format is probably the most portable format due to support being built into certain Operating Systems ;-). Plus, the OP specifically asked for a .zip format example in the question.
    – TrinitronX
    Commented Mar 11, 2014 at 21:23

You may use Ant for that.

Create a file named build.xml:

<project name="zip-utils">

    <target name="add-file-to-zip">
        <fail message="Property 'zip' must be set" unless="zip" />
        <fail message="Property 'file' must be set" unless="file" />
        <fail message="Property 'path' must be set" unless="path" />

        <available file="${zip}" property="zip.exists" />
        <fail message="Zip file missing: ${zip}" unless="zip.exists" />

        <available file="${file}" property="file.exists" />
        <fail message="File missing: ${file}" unless="file.exists" />

        <dirname property="file.dir" file="${file}"/>
        <basename property="file.filename" file="${file}"/>

        <zip destfile="${zip}" update="true">
            <zipfileset fullpath="${path}" dir="${file.dir}" includes="${file.filename}"/>


Then, in the same dir of build.xml, you may run it using something like:

ant add-file-to-zip -Dzip=foo.zip -Dfile=file.txt -Dpath=/very/many/paths/file.txt

You must log in to answer this question.

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