How to Zip and Unzip Files from the Command Line

On Windows, zip a folder with Compress-Archive -Path project -DestinationPath project.zip in PowerShell and unzip with Expand-Archive project.zip -DestinationPath out. On macOS and Linux, use zip -r project.zip project and unzip project.zip, or tar -czf project.tar.gz project and tar -xzf project.tar.gz for a compressed tarball.

How to zip and unzip on Windows with PowerShell

Compress-Archive -Path project -DestinationPath project.zip
Expand-Archive -Path project.zip -DestinationPath out

Both commands are built into Windows PowerShell 5.1 and PowerShell 7 and print nothing on success. Some details that trip people up:

  • Folder or contents. -Path project stores the folder itself, so the zip contains project/readme.txt. -Path project\* stores only what is inside it.
  • Existing files are not overwritten. Running the same command twice fails with The archive file ...\project.zip already exists. Use the -Update parameter to update the existing archive file or use the -Force parameter to overwrite the existing archive file. Expand-Archive similarly refuses to overwrite extracted files until you add -Force.
  • No destination given. Expand-Archive project.zip extracts into a new folder named after the zip, in the current directory.
  • Hidden files are skipped. Microsoft's documentation: Compress-Archive "ignores hidden files and folders when creating or updating the archive file".
  • 2 GB limit. Both cmdlets use .NET's ZipArchive API, which "limits the maximum file size to 2GB".
  • Backslashes in Windows PowerShell 5.1. On our Windows 11 test, a zip made by Compress-Archive in PowerShell 5.1 stored its paths as project\docs\notes.md. Info-ZIP's unzip still extracted it correctly, but warned appears to use backslashes as path separators and exited with status 1, which can break scripts on the receiving end. tar (below) writes forward slashes.

Add -CompressionLevel Fastest for speed or NoCompression for files that are already compressed (videos, JPEGs); the default is Optimal.

How to use tar on Windows 10 and 11

Windows has shipped tar.exe since Windows 10 Insider build 17063, and it works from Command Prompt and PowerShell. It is bsdtar from the libarchive project (the test machine reports bsdtar 3.7.7 - libarchive 3.7.7), which can also read and write zip files. That makes it the way around the PowerShell limits above:

tar -a -cf project.zip project      # create a zip (format chosen from the .zip extension)
tar -xf project.zip                 # extract a zip into the current folder
tar -xf project.zip -C out          # extract into an existing folder named out
tar -czf project.tar.gz project     # create a gzip-compressed tarball

The -a option picks the format from the file name, which is how tar knows to write a zip instead of a tarball.

How to zip and unzip on macOS and Linux

zip -r project.zip project
unzip project.zip

-r tells zip to "travel the directory structure recursively". Without it, zip doesn't descend into the folder, so the files inside are left out. Useful variations:

zip -r project.zip project -x '*.log'   # exclude files matching a pattern
unzip project.zip -d out                # extract into the folder out
unzip -o project.zip                    # overwrite existing files without asking
unzip -n project.zip                    # never overwrite existing files

macOS normally comes with zip and unzip. Many Linux installs don't: in our Ubuntu 22.04 WSL install, both zip and unzip gave command not found. Install them with sudo apt install zip unzip on Debian and Ubuntu, or sudo dnf install zip unzip on Fedora. tar is always there.

How tar -czf and -xzf work

A tarball is created and extracted with letter flags that combine:

FlagMeaning
cCreate a new archive
xExtract an archive
tList an archive's contents
zCompress or decompress with gzip (.tar.gz, .tgz)
j / JUse bzip2 (.tar.bz2) / xz (.tar.xz) instead
vVerbose: print each file as it is processed
fThe next argument is the archive file name
C dirChange to dir first (extract into it, or archive from it)
tar -czf project.tar.gz project      # create
tar -xzf project.tar.gz              # extract here
tar -xzf project.tar.gz -C /tmp      # extract into /tmp

Keep f last in the group, because the archive name must follow it directly. We tried tar -cfz bad.tar project with GNU tar: it created an archive named z and failed with tar: bad.tar: Cannot stat: No such file or directory. When extracting, both GNU tar (in Git Bash) and Windows' bsdtar detected gzip on their own in our tests, so tar -xf project.tar.gz works without z.

How to list a zip or tar file without extracting it

unzip -l project.zip           # macOS, Linux, Git Bash
tar -tf project.zip            # Windows 10/11, macOS, Linux (bsdtar reads zip)
tar -tzvf project.tar.gz       # tarball, with sizes and permissions

Real output of unzip -l on a zip created with tar -a -cf:

Archive:  viatar.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2026-10-26 12:14   project/
        0  2026-10-26 12:14   project/docs/
        7  2026-10-26 12:14   project/readme.txt
        7  2026-10-26 12:14   project/docs/notes.md
---------                     -------
       14                     4 files

Listing first is a good habit with archives from elsewhere: it shows whether everything is inside a single top-level folder or will spill files into your current directory. unzip -t project.zip goes one step further and tests every file's checksum without writing anything. PowerShell has no built-in listing cmdlet; use tar -tf there.

Password-protected zip files: a caveat

zip -e prompts for a password and encrypts the archive:

zip -r -e secret.zip project

By default this uses the original PKZIP encryption, often called ZipCrypto, which the zip manual itself calls "the relatively weak standard encryption provided by zipfile utilities". Treat it as a lock against casual opening, not as protection for sensitive data. Avoid putting the password on the command line with -P; both the zip and unzip manuals warn "THIS IS INSECURE!" because other users can see command lines and scripts store them in plain text. Compress-Archive has no password option at all.

For real encryption, use 7-Zip, whose features include "Strong AES-256 encryption in 7z and ZIP formats". Its documentation lists ZipCrypto as the default encryption method for zip files, and in our test with 7-Zip 23.01, 7z l -slt reported Method = ZipCrypto Store for a zip made with just -p. Ask for AES explicitly:

7z a -tzip -p -mem=AES256 secret.zip project   # AES-256 zip; prompts for the password
7z a -p -mhe=on secret.7z project              # 7z format; -mhe also hides file names

With -p and no password after it, 7z asks Enter password (will not be echoed):. The same listing then shows Method = AES-256 Store. The trade-off is compatibility: Info-ZIP's unzip 6.00 refused to extract our AES zip (need PK compat. v5.1 (can do v4.6)), so make sure the recipient has 7-Zip or another AES-capable tool. Whichever method you use, send the password through a different channel from the file.

If an archive won't extract

  • "End-of-central-directory signature not found" from unzip, or a "not a valid zip" error: the file is incomplete or not a zip. Re-download it and compare its SHA-256 with the published one; the larely checksum tool calculates it in the browser without uploading the file.
  • "gzip: stdin: not in gzip format" from tar -xzf: the file isn't gzip-compressed despite its name. Run file name.tar.gz on macOS or Linux to see what it really is, then drop the z.
  • Garbled file names after extracting an old zip: older tools stored names in a local code page rather than UTF-8. Microsoft notes Expand-Archive uses the raw stored value in that case; 7-Zip usually handles these better.

Frequently asked questions

What is the difference between .zip and .tar.gz?
A zip file compresses each file separately and keeps an index, so you can list or extract one file quickly. A .tar.gz first joins all files into one tar stream and then compresses the whole stream with gzip, which often gives a smaller result for many similar files and keeps Unix permissions, but extracting one file means reading through the archive. Zip is the usual choice for sharing with Windows users; tar.gz is common for Linux software and backups.
Why does Compress-Archive fail on large files?
Microsoft documents that Compress-Archive and Expand-Archive use the .NET System.IO.Compression.ZipArchive API, which limits the maximum file size to 2 GB. For bigger files, use tar -a -cf archive.zip on Windows 10 and 11, or 7-Zip.
How do I zip a folder without including the folder itself?
In PowerShell, add \* to the path: Compress-Archive -Path C:\project\* -DestinationPath project.zip. With zip on macOS and Linux, change into the folder first and zip its contents: cd project && zip -r ../project.zip . With tar, use -C: tar -czf project.tar.gz -C project .
Are hidden files included?
Not with Compress-Archive: Microsoft's documentation says it ignores hidden files and folders, including names starting with a dot on macOS and Linux. zip -r and tar include hidden files and dotfiles inside the folders you give them.

Sources