6

Given a bunch of files in the current directory, I want to be able to zip them such that, when extracted, they'd be placed in some given directories. For example, say I have these in $PWD:

ls
fsck
xz
chroot

And when I run unzip foo.zip, they each get extracted to these directories:

/bin
/sbin
/usr/bin
/usr/sbin

The closest I could find is that these files must already exist in whatever directory paths I want the files to be extracted to (using $PWD as root directory):

$ zip foo.zip bin/ls sbin/fsck usr/bin/xz usr/sbin/chroot

Then, on a system where I want this extraction to happen, I would have to:

$ cd /
$ sudo unzip foo.zip
  • 1
    it makes sense that a zip file can't contain absolute destination paths, otherwise this would be a security issue (i.e., uncompressing a zip file could maliciously replace system files). As a proof of concept, it could replace the .ssh/authorized_keys file. – pqnet Aug 12 '14 at 2:58
4

I don't see a way to do this using the zip command, but it's easy in python.

Note that the zip file format specification, section 4.4.17.1, says that the pathname cannot start with a '/', so I can't help with that part.

The python zipfile module will let you override a file's pathname when you add it to the zip archive; just pass the desired name as the optional 2nd argument to ZipFile.write:

ZipFile.write(filename[, arcname[, compress_type]])
Write the file named filename to the archive, giving it the archive name arcname (by default, this will be the same as filename, but without a drive letter and with leading path separators removed). If given, compress_type overrides the value given for the compression parameter to the constructor for the new entry.
Note: Archive names should be relative to the archive root, that is, they should not start with a path separator.

Here's an example:

$ touch 1 2 3
$ python
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
>>> import zipfile
>>> with zipfile.ZipFile('bundle.zip', 'w') as bundle:
...   bundle.write('1', '/bin/1')
...   bundle.write('2', '/sbin/2')
...   bundle.write('3', '/usr/bin/3')
... 
>>> 
$ unzip -l bundle
Archive:  bundle.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2014-08-11 13:00   bin/1
        0  2014-08-11 13:00   sbin/2
        0  2014-08-11 13:00   usr/bin/3
---------                     -------
        0                     3 files

Note that zipfile.write will remove any leading '/' from the pathname, to conform with the standard.

  • This still requires one to cd to / directory before extracting. – Tshepang Aug 11 '14 at 22:43
  • @Tshepang Yes, the zip file format specification says that the pathname cannot start with a '/'. If you give zipfile.write a pathname that starts with '/', it will be removed. I've edited my answer to add this. – Mark Plotnick Aug 12 '14 at 2:27
  • to create such a zip wouldn't be sufficient to create the directory structure inside a temporary dir, hard linking the needed files, and then generate the zip file from there? – pqnet Aug 12 '14 at 2:56
  • @pqnet I mentioned that approach in my Question. – Tshepang Aug 12 '14 at 8:20
  • 1
    @Tshepang sorry I misunderstood your words thinking that you would actually use the root directory. What I meant to say is that unless you are using python as packaging tool (so that you don't have to parse the lists) this solution is pretty much the same thing. – pqnet Aug 12 '14 at 8:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.