Troubleshooting

unzip: command not found — install unzip and zip on any server

unzip and zip are separate packages minimal images leave out. Install them on Debian, Ubuntu, Rocky, Alpine and Docker, or extract with python3 or bsdtar.

Published ~7 min read

Quick fix: unzip is not installed, so add it with your package manager: sudo apt update && sudo apt install -y unzip zip on Debian and Ubuntu, sudo dnf install -y unzip zip on Rocky, AlmaLinux, RHEL and Fedora, or apk add unzip zip on Alpine (macOS already ships both). If you cannot install anything, python3 -m zipfile -e archive.zip outdir/ extracts the archive with nothing but Python.

bash: unzip: command not found turns up on a fresh server the first time you upload a website, a plugin or a release archive. unzip and zip are two small, separate packages, and cloud images, minimal installs and container bases such as debian:*-slim, ubuntu and the Rocky and Alma minimal images leave both out. Nothing is broken; the tool was never there. Check which system you are on, then install the pair.

diagnose
command -v unzip; command -v zip      # a path for each one that exists, nothing otherwise
grep -E '^(ID|VERSION_ID)=' /etc/os-release

How do I install unzip on each distribution?

Install zip at the same time. It costs a few hundred kilobytes, and the next thing you do after extracting a site is usually packing up a backup.

Debian and Ubuntu

Refresh the package index first. On a fresh image the index is often empty, and apt then reports Unable to locate package unzip, a second error with the same cause.

Debian · Ubuntu
sudo apt update
sudo apt install -y unzip zip

Rocky, AlmaLinux, RHEL and Fedora

Rocky · Alma · RHEL · Fedora
sudo dnf install -y unzip zip

# minimal container images that only have microdnf
microdnf install -y unzip zip

On an old CentOS 7 box the same command works with yum in place of dnf. If neither exists, see yum: command not found for which package manager your system actually uses.

Alpine

Alpine already has a small unzip built into BusyBox. It lists, tests and extracts ordinary archives (-l, -t, -o, -n, -j, -x, -d), but it cannot open password-protected entries (it stops with zip flag 1 (encryption) is not supported) and BusyBox has no zip at all. Install the full Info-ZIP tools when you need either:

Alpine
apk add --no-cache unzip zip

Arch, openSUSE and macOS

Arch · openSUSE · macOS
# Arch, Manjaro
sudo pacman -S --needed unzip zip

# openSUSE
sudo zypper install -y unzip zip

# macOS ships /usr/bin/unzip and /usr/bin/zip; ditto can extract too
ditto -x -k archive.zip destination/

How do I get unzip inside a Docker image?

Install it in the Dockerfile, not in a running container: anything you add by hand disappears when the container is recreated. Inside an image build you are root, so there is no sudo.

Dockerfile · Debian or Ubuntu base
RUN apt-get update \
 && apt-get install -y --no-install-recommends unzip \
 && rm -rf /var/lib/apt/lists/*
Dockerfile · Alpine or Rocky base
# Alpine
RUN apk add --no-cache unzip

# Rocky / Alma / UBI minimal
RUN microdnf install -y unzip && microdnf clean all

Slim images leave out other everyday tools in the same way, and some of them do not even have ps; see ps: command not found.

Can I extract a ZIP without installing unzip?

Yes. Three tools you may already have can read ZIP archives:

no unzip needed
# Python 3 (present on most servers)
python3 -m zipfile -l archive.zip            # list
python3 -m zipfile -e archive.zip outdir/    # extract

# bsdtar (libarchive) reads ZIP as well as tar
bsdtar -xf archive.zip -C outdir/

# a JDK's jar tool extracts into the current directory
jar xf archive.zip
  • Python’s zipfile does not restore Unix permissions, so a script that was executable in the archive comes out as a plain file. Run chmod +x on it afterwards.
  • bsdtar keeps the permissions. It is in libarchive-tools on Debian, Ubuntu and Alpine and in bsdtar on Rocky, Alma and Fedora. On macOS the normal tar command is bsdtar, so tar -xf archive.zip works there out of the box.

Which unzip and zip commands will you actually use?

unzip
unzip -l archive.zip                     # list the contents, extract nothing
unzip -t archive.zip                     # test the archive for damage
unzip archive.zip -d /var/www/site       # extract into a directory
unzip -o archive.zip                     # overwrite existing files without asking
unzip -n archive.zip                     # never overwrite existing files
unzip -q archive.zip                     # quiet
unzip archive.zip 'wp-content/*'         # extract only the matching paths

-d creates the last directory in the path but not missing parents: unzip site.zip -d /srv/new/site fails with checkdir: cannot create extraction directory when /srv/new does not exist yet. Run mkdir -p on the path first.

zip
zip -r site.zip public_html/                                   # a whole directory
zip -r site.zip public_html/ -x 'public_html/cache/*' '*.log'   # with exclusions
zip -u site.zip public_html/index.php                          # update one file in place

Why does unzip say “cannot find zipfile directory”?

The full message looks like this, and it ends with exit code 9:

the error
End-of-central-directory signature not found.  Either this file is not
a zipfile, or it constitutes one disk of a multi-part archive. ...
unzip:  cannot find zipfile directory in one of archive.zip or
        archive.zip.zip, and cannot find archive.zip.ZIP, period.

A ZIP file keeps its table of contents at the very end. If unzip cannot find it, the file is not a complete ZIP archive. Almost always that is one of two things: the download stopped early, or what you saved is an HTML page, such as a login screen, a 404 page or a “confirm download” page, with .zip on its name. Check before you try anything else:

what did I actually download?
ls -l archive.zip          # a few KB for a "50 MB" release is a give-away
file archive.zip           # "HTML document" means it is a web page
head -c 300 archive.zip    # read the start if file is not installed

Then download it again in a way that fails loudly. curl -f stops on an HTTP error instead of saving the error page, and -L follows the redirects that release links almost always use:

download properly
curl -fL -o archive.zip https://example.com/release.zip
unzip -t archive.zip

If curl is missing as well, see curl: command not found, or use wget, which does not save a 404 page by default. A file that is really one part of a split archive (.z01, .z02…) needs all of its parts in the same directory.

How do I fix garbled file names from Windows ZIPs?

Archives made by older Windows tools store non-English file names in a legacy code page instead of UTF-8, so Cyrillic or Chinese names come out as mojibake. The unzip shipped by Ubuntu and by the RHEL family has a -O option for this. Debian’s unzip does not: the builds in Debian 12 and 13 lack the patch that adds it.

Ubuntu · Rocky · Alma
unzip -O cp866 archive.zip     # Russian (DOS code page)
unzip -O cp936 archive.zip     # Simplified Chinese (GBK)
unzip -O cp932 archive.zip     # Japanese (Shift-JIS)
Debian 12 and 13
# Python 3.11 or newer
python3 -m zipfile --metadata-encoding cp866 -e archive.zip outdir/

# or unar, which guesses the encoding and takes -e to override it
sudo apt install -y unar
unar -e cp866 archive.zip

On minimal Rocky and Alma images the names can stay garbled even with -O, because the code-page converters live in a separate package that minimal installs leave out. sudo dnf install -y glibc-gconv-extra adds them. Archives made by current tools mark their names as UTF-8 and need none of this.

Can unzip handle large archives, and how much space do I need?

UnZip 6.0 and Zip 3.0, the versions every current distribution ships, support Zip64, so archives over 4 GB or with more than 65,535 entries are fine. The usual problem is space: extracting needs room for the full uncompressed size, on top of the archive itself. The last line of a listing gives you that total before you start.

will it fit?
unzip -l archive.zip | tail -1    # total uncompressed size, in bytes
df -h /var/www                    # free space where you are extracting

If an extraction dies halfway with a write error, read No space left on device.

Why is unzip still “not found” after installing it?

Run hash -r (bash) or rehash (zsh), or open a new terminal, then check command -v unzip. When a script calls unzip on a machine without it, that command fails with status 127, so a CI job or install script that “failed with 127” is very often this exact error. See exit code 127 for how to read those.

Should I move a website as a ZIP or a tarball?

ZIP is what most panels export, but between two Linux servers a tarball is the better format: run as root, tar restores ownership and permissions by default, while unzip restores ownership only when you add -X. Our guide to moving from shared hosting to a VPS uses tar and rsync for that reason.

If your site runs on Plesk web hosting, you do not need a shell for this at all: Plesk’s File Manager unpacks an uploaded ZIP with Extract Files. And if you deploy from archives regularly, a small Standard KVM VPS is a cheap, disposable place to unpack and test a release before it reaches the production server.

Another tool missing, or a directory to add to PATH for good in bash, zsh and fish? See command not found: the three causes and the fix for every tool.

Frequently asked

Why is unzip not installed on Ubuntu Server?

Nothing in a server install needs it. Ubuntu's server and minimal package sets do not pull unzip in, Debian marks both unzip and zip as optional, and cloud and container images drop everything optional. Install the pair with 'sudo apt update && sudo apt install -y unzip zip'.

How do I unzip a file without installing anything?

Use Python, which almost every server has: 'python3 -m zipfile -e archive.zip outdir/'. It does not restore Unix permissions, so chmod +x any scripts afterwards. bsdtar ('bsdtar -xf archive.zip') also reads ZIP files, and on macOS plain 'tar -xf archive.zip' works.

How do I unzip into a specific folder?

Run 'unzip archive.zip -d /path/to/folder'. unzip creates the last directory in that path but not missing parents, so run 'mkdir -p /path/to/folder' first for a deeper path, or it stops with 'checkdir: cannot create extraction directory'.

Why does unzip say 'cannot find zipfile directory'?

The file is not a complete ZIP archive. Usually the download stopped early or you saved an HTML error or login page under a .zip name. Check it with 'file archive.zip' and its size, then download it again with 'curl -fL -o archive.zip <url>' so HTTP errors fail instead of being saved.

Related articles

All troubleshooting