How to extract a zip file on a Mac: doing it without extra software

Double-clicking a zip file on a Mac usually works, which is why the question only comes up when it does not. The archive expands into a folder nobody asked for, or it stops halfway with an error that names no file, or the names inside come out as strings of question marks, or the whole thing is 40 GB and only one file inside it is needed. macOS ships with everything required to handle all of those cases. The tools are just not in the Finder.

This walks through what the double-click actually does, where it stops being the right tool, and which of the built-in commands to reach for instead.

What happens when a zip file is double-clicked

The Finder does not expand archives itself. It hands the file to Archive Utility, a small application that lives at /System/Library/CoreServices/Applications/Archive Utility.app. It has no window and no dock icon under normal use, which is why the behaviour feels like it belongs to the Finder.

Archive Utility makes two decisions without asking. It extracts into the same directory as the archive, and it names the output after the archive. If photos.zip contains loose files rather than a single top-level folder, those files land next to the archive. A hundred-file archive dropped into the Downloads folder will scatter a hundred items across it, and there is no undo.

Its behaviour can be changed, but not from the Finder. Opening Archive Utility directly, through Spotlight or open -a "Archive Utility", gives a Settings window with options for where expanded items go and what to do with the archive afterwards. The setting is sticky and applies to every later double-click, which makes it worth setting once: expanding into a chosen folder rather than the archive's own directory removes the scattering problem entirely.

The other thing Archive Utility does silently is stop on failure. When an archive is truncated or a single entry is corrupt, the dialog says the operation could not be completed and gives an error number. It does not say which entry failed, and it does not offer to keep the entries it already read. That single limitation is the reason the terminal route exists.

The three commands macOS already has

Three separate extractors ship with every Mac, and they are not interchangeable.

Command Handles Notable behaviour
unzip zip only Info-ZIP UnZip 6.00, dated 2009, with Apple modifications. Can list and extract selectively.
ditto zip, plus plain copying Apple's own tool. Preserves resource forks and metadata.
tar tar, gz, bz2, xz, zip, 7z, cpio, iso bsdtar, built on libarchive. Reads far more formats than its name suggests.

The plainest form is the one most people want:

unzip archive.zip -d ~/Extracted

The -d flag is the part worth remembering. Without it, unzip expands into the current working directory, which reproduces the scattering problem. With it, the destination folder is created if it does not exist.

Looking before extracting costs one command and saves cleanup:

unzip -l archive.zip

That prints every entry with its size and date without writing anything to disk. For an archive from an unknown source, it is the first thing to run. It answers whether there is a single top-level folder, how many entries there are, and whether anything inside has an unexpected path.

ditto is the one to use when the archive was made on a Mac and might carry Mac-specific metadata:

ditto -x -k archive.zip ~/Extracted

Here -x means extract and -k means treat the source as a zip archive rather than a directory. Unlike unzip, ditto understands the convention macOS uses to store resource forks inside zip files, and it reassembles them instead of leaving them as separate files.

Getting one file out of a large archive

Full extraction is often unnecessary. Both unzip and tar can pull a subset.

With a known path inside the archive:

unzip archive.zip "docs/contract.pdf" -d ~/Extracted

With a pattern, to get every PDF regardless of where it sits:

unzip archive.zip "*.pdf" -d ~/Extracted

The quotes matter. Without them the shell expands the pattern against the current directory before unzip ever sees it, and the result is either the wrong files or no match at all.

The inverse is -x, which extracts everything except what is listed:

unzip archive.zip -x "*.mov" -d ~/Extracted

For an archive that a full extraction cannot finish, unzip keeps going where Archive Utility stops. Running it in the terminal prints a line per entry, so the failure is attributable to a specific file, and everything read before that point is already on disk. That alone is often the difference between recovering most of an archive and recovering none of it.

The __MACOSX folder, and why it appears

Extracting a Mac-made archive on a Mac is quiet. Extracting one on Windows or Linux produces a __MACOSX folder full of files whose names start with ._, and the recipient usually asks about it.

Those files are resource forks and extended attributes, split out into a parallel tree. The mechanism is visible in the command macOS itself uses to build such an archive:

ditto -c -k --sequesterRsrc --keepParent source_folder archive.zip

--sequesterRsrc is what creates the __MACOSX tree. Listing the result shows both trees side by side: the real files under their own folder, and a matching ._name entry under __MACOSX. On extraction with ditto, the two halves are recombined and the parallel tree disappears. On extraction with any tool that does not know the convention, both halves land as ordinary files.

Sending an archive to someone on another platform is therefore a reason to build it differently:

zip -r archive.zip source_folder -x ".DS_Store"

The bundled zip is Info-ZIP 3.0 from 2008, also with Apple modifications. It writes a plain archive with no parallel tree. The -x excludes the Finder's .DS_Store files, which are otherwise carried along and mean nothing to the recipient. The trade-off is real: anything that genuinely depends on resource forks will not survive the round trip. For ordinary documents, images and code, nothing is lost.

Filenames that come out wrong

The most common failure that looks like corruption is not corruption. An archive created on a Japanese or Chinese Windows machine stores its filenames in a legacy encoding rather than UTF-8. The bundled unzip has no option to specify an encoding, and the version string explains why: UnZip 6.00 dates from April 2009, before that support was added upstream. Names come out as mojibake, and no flag fixes it.

The workaround is to use a tool that does handle it. The Finder's Archive Utility applies its own heuristics and often gets these names right where unzip does not, which is one of the few cases where the double-click route is the better one. Failing that, tar reads zip archives through libarchive and accepts an options flag for the character set:

tar --options hdrcharset=CP932 -xf archive.zip -C ~/Extracted

Two other limits produce surprises on extraction. A single filename component cannot exceed 255 characters on macOS, and archives built on systems with longer limits will fail on those entries specifically. And APFS is case-insensitive by default, so an archive containing both Report.txt and report.txt cannot fully extract: one overwrites the other. Listing the archive first with unzip -l and scanning for near-duplicate names catches this before it happens rather than after.

Archives that are not zip files

Half the files that arrive with an expand-me shape are not zip archives. tar handles most of them without being told which format it is looking at:

tar -xf archive.tar.gz -C ~/Extracted
tar -xf archive.tar.xz -C ~/Extracted
tar -xf archive.7z -C ~/Extracted

The version that ships with macOS is bsdtar built on libarchive, and its format support extends well past tar: gzip, bzip2, xz, zip, 7-Zip, cpio, ISO images and more. Checking what a file actually is takes one command:

file mystery-download

RAR is the notable gap. macOS has no bundled extractor for it, and neither Archive Utility nor tar will open one, so a RAR archive is the case where something has to be installed. Encrypted zip archives are handled: unzip prompts for the password when it reaches the first encrypted entry, and -P accepts one on the command line, though that leaves the password in shell history.

Disk images are a different category that often gets mistaken for archives. A .dmg file is mounted rather than extracted, either by double-clicking or with hdiutil attach image.dmg, and it appears as a volume until it is ejected. Treating one as an archive and trying to expand it produces an error that says nothing useful about what is actually wrong. The same applies to installer packages ending in .pkg, which are archives internally but are meant to be run rather than unpacked, and to application bundles, which look like single files in the Finder but are ordinary folders underneath.

Multi-part archives show up in downloads split across several files, named with suffixes such as .z01 and .z02 alongside a final .zip. All the parts have to sit in the same directory, and the command points at the last one rather than the first. Missing a single part means the set cannot be read at all, which is worth checking before concluding that the archive is damaged.

Handling many archives at once

A folder of archives is where the Finder route stops scaling. Double-clicking twenty zip files means twenty dialogs, twenty output folders named after the archives, and no record of which one failed. A loop does the same job and reports properly:

for f in *.zip; do unzip -q "$f" -d "${f%.zip}"; done

The -q suppresses the per-entry listing so that only errors surface, and ${f%.zip} strips the extension to name each destination folder. Anything that fails prints its own line, and the archives that succeeded are already extracted.

The same shape works for listing without extracting, which is useful when the question is what is inside a batch rather than getting it out:

for f in *.zip; do echo "== $f"; unzip -l "$f" | tail -3; done

That prints the entry count and uncompressed total for each archive. Reading twenty of those lines is faster than opening twenty folders, and it shows immediately which archive is the 40 GB one.

Nested archives are the other case worth naming. Zip files containing zip files are common in exports from web services, and no tool unwraps them recursively on its own. Extracting the outer layer first and then looping over the result handles two levels, which covers nearly every real export.

Checking an archive before trusting it

Two habits prevent most extraction problems.

The first is listing before extracting. unzip -l on an unknown archive takes a second and shows whether entries use absolute paths or ../ segments, either of which would write outside the destination folder. Extraction tools guard against this, but knowing the shape of an archive before it lands is cheaper than sorting out where things went.

Absolute paths inside archives are rarer than they used to be but still turn up in archives produced by older backup tools. An entry recorded as /Users/someone/Documents/file.txt rather than Documents/file.txt is a sign the archive was built without stripping the leading component, and the listing shows it plainly. Modern extractors strip the leading slash and warn about it, so nothing escapes the destination folder, but the resulting directory structure is deeper and stranger than expected.

The second is checking size against free space. A zip archive of text or log files can expand by a factor of ten or more, and there is no warning before the disk fills. unzip -l prints the uncompressed total at the bottom, and df -h ~ prints what is available. Comparing the two numbers is faster than recovering from a full startup disk.

What to change first

Set Archive Utility's destination once, so double-clicking never scatters files again, and learn unzip -l as the reflex before extracting anything from outside. Those two changes cover most of what goes wrong. If the deeper annoyance is that inspecting an archive means one window and extracting it means another, that is a layout problem rather than an archive problem, and a file manager that keeps the folder view and the shell in the same place removes the switch: Atriens is built on that arrangement, and Compared with other file managers sets out where it sits against the alternatives.

Frequently asked questions

Why does the double-click fail when the terminal command works?

Archive Utility stops at the first entry it cannot read and discards what it had already extracted. unzip prints a line per entry and keeps everything it managed to read before the failure, so a partly damaged archive still yields most of its contents. The error also names the specific file, which Archive Utility does not.

How do you extract a zip file without creating a folder?

Use unzip archive.zip -d . to expand into the current directory, or set the destination explicitly with -d ~/somewhere. Whether a folder appears depends on the archive: if it was built with a single top-level folder inside, that folder is part of the archive's contents and every tool will recreate it.

Is it safe to delete the __MACOSX folder after extracting?

For ordinary documents, images, video and source code, yes. It holds resource forks and extended attributes such as Finder tags, which those file types do not depend on. Older Mac-specific formats and some font files can rely on resource forks, so check that the files open correctly before removing it.

Can macOS open RAR files without installing anything?

No. Archive Utility does not handle RAR, and the bundled tar does not either, despite reading many other formats. RAR is the main case where third-party software is genuinely required. Checking the file first with the file command confirms the format before assuming the extraction failed for another reason.

What causes filenames to appear as question marks or random symbols?

The archive stores filenames in a legacy encoding rather than UTF-8, which is common for archives created on Japanese or Chinese Windows systems. The bundled unzip dates from 2009 and has no flag for specifying an encoding. Archive Utility often guesses correctly, and tar --options hdrcharset=CP932 handles the most common case explicitly.

Back to all posts