Andrew Mercer
on this page

zip and unzip

Format: .zip · Algorithm: per-file DEFLATE (store, bzip2, LZMA, zstd and others are allowed by the spec) · First released: 1989 (Phil Katz, PKWARE)

ZIP is the one archive format every operating system opens natively, which makes it the right choice for handing files to non-technical users. Each member is compressed separately, so you get fast random access but a worse ratio than a solid tarball on many small similar files.

Many other formats are ZIP files underneath: .jar, .war, .apk (Android), .docx, .xlsx, .pptx, .odt, .epub, and Python .whl.

On Linux, zip and unzip come from the Info-ZIP project.

Creating archives

zip -r archive.zip src_dir/
zip -r -9 archive.zip src_dir/                       # max compression
zip -r -0 archive.zip src_dir/                       # store only
zip -r archive.zip src_dir/ -x '*.git*' '*/node_modules/*'
zip -r -y archive.zip src_dir/                       # store symlinks as links
zip -r -n .jpg:.png:.mp4 archive.zip media/          # don't recompress these
zip -j flat.zip dir/*/*.txt                          # junk paths
zip -r -s 100m split.zip big_dir/                    # 100 MB volumes

Modifying archives

zip -u archive.zip changedfile          # update changed / add new
zip -f archive.zip                      # freshen: update only existing members
zip -d archive.zip 'path/to/remove'     # delete a member
zip -FS -r archive.zip src_dir/         # sync: also remove deleted files

Extracting

unzip archive.zip
unzip archive.zip -d /tmp/dest          # into a directory
unzip archive.zip 'docs/*'              # only matching members
unzip -j archive.zip                    # junk paths (flatten)
unzip -o archive.zip                    # overwrite without prompting
unzip -n archive.zip                    # never overwrite
unzip -p archive.zip file.txt | less    # one member to stdout

Inspecting

unzip -l archive.zip                    # list
unzip -v archive.zip                    # list with ratios and CRCs
unzip -t archive.zip                    # test integrity
zipinfo archive.zip                     # detailed listing
zipgrep 'pattern' archive.zip           # grep inside members

Encryption (and why it's weak)

zip -r -e archive.zip src_dir/          # same as --encrypt; prompts for a password
zipcloak archive.zip                    # encrypt an existing archive

Info-ZIP's -e uses the legacy ZipCrypto scheme, which is cryptographically broken: known-plaintext attacks recover the keys quickly. Filenames aren't encrypted either. Treat it as a lock that keeps honest people out.

For real protection:

  • AES-256 zip via 7-Zip: 7z a -tzip -p -mem=AES256 secret.zip src_dir/ (filenames still visible)
  • 7z with header encryption: 7z a -p -mhe=on secret.7z src_dir/
  • age or gpg on a tarball — see encryption

Splitting and joining

zip -r -s 100m split.zip big_dir/       # split.z01, split.z02, ..., split.zip
zip -s 0 split.zip --out joined.zip     # rejoin
unzip joined.zip

Gotchas

  • Filename encoding: archives from older Windows tools may use a legacy codepage. Some unzip builds accept -O CP437 (or the right codepage) to fix garbled names; 7-Zip and unar often handle this automatically.
  • Zip64: archives over 4 GiB or with more than 65,535 entries need Zip64. Info-ZIP 3.0 handles it, but very old tools can't read the result.
  • Permissions: Unix modes are stored in extra fields and restored by Info-ZIP, but not by every tool. Owners and groups aren't preserved. Use tar for system backups.
  • Hard links and special files aren't preserved.
  • macOS archives may contain __MACOSX/ and ._* files: zip -d archive.zip '__MACOSX/*' removes them. See macOS and Windows.
  • Zip slip: malicious entries like ../../etc/x. Info-ZIP strips ../ components, but always list untrusted archives first. See gotchas.

See also