Every so often I stumble onto an old .Z file — usually inside some legacy archive, an ancient Unix backup, or a decades-old software distribution — and I have to remind myself that uncompress even exists, because it’s genuinely rare to encounter in modern day-to-day Linux use. Still, it’s worth knowing properly, both because you’ll eventually run into a .Z file somewhere and because it’s a great window into how Unix compression tooling evolved into what we use today (gzip, xz, zstd).
Here’s my complete rundown of uncompress — syntax, internals, and where it still matters.
What uncompress Does
uncompress decompresses files that were compressed with the compress utility, which produces files ending in .Z. The compress algorithm is based on LZW (Lempel-Ziv-Welch), the same compression method that was also famously used in the original GIF format. compress/uncompress predate gzip by years and were the standard Unix compression tool throughout the 1980s and early 1990s.
On most modern Linux distributions, the “real” compress/uncompress binaries come from the ncompress package. Interestingly, many systems also ship a compatibility shim: gunzip itself can decompress .Z files, and some distributions install uncompress as a small wrapper script around gzip for exactly this reason. I confirmed this directly on a fresh Ubuntu container — before installing ncompress, /usr/bin/uncompress already existed as a shell script that called into the gzip codebase:
$ cat /usr/bin/uncompress | head -5
#!/bin/sh
# Uncompress files. This is the inverse of gzip.
After installing the actual ncompress package (apt-get install ncompress), you get the true LZW-based implementation.
Basic Syntax
uncompress [options] file.Z [file2.Z ...]
By default, uncompress replaces the .Z file with its decompressed version, removing the .Z extension.
Testing It in Practice
I ran this test to confirm the round trip works cleanly:
$ cp sample.txt compresstest.txt
$ compress compresstest.txt
$ ls -la compresstest.txt.Z
-rw-r--r-- 1 root root 584 Jul 31 01:37 compresstest.txt.Z
$ uncompress compresstest.txt.Z
$ ls -la compresstest.txt
-rw-r--r-- 1 root root 2226 Jul 31 01:37 compresstest.txt
Notice the original compresstest.txt (2226 bytes) was compressed down to compresstest.txt.Z (584 bytes), and uncompress restored it to the original 2226-byte file, with the .Z extension gone entirely.
Parameters and Options
| Option | Description |
|---|---|
-c | Write decompressed output to standard output, leaving the original .Z file untouched |
-f | Force decompression, overwriting an existing output file without prompting |
-v | Verbose mode; print the percentage reduction and filenames as it works |
-r | Recursively decompress files in a directory tree (GNU/ncompress extension) |
A common pattern I use to keep the original archive intact while inspecting its contents:
$ uncompress -c compresstest.txt.Z > /tmp/preview.txt
$ diff /tmp/preview.txt compresstest.txt 2>/dev/null || echo "differs or original missing"
Since I already removed compresstest.txt.Z in the earlier round trip, this specific comparison would need a fresh .Z file, but the pattern is exactly how I handle any compressed file I don’t want to destroy while checking its content.
How compress/uncompress Work Internally
The LZW algorithm that compress uses builds a dictionary of byte sequences as it scans through the input, replacing repeated sequences with shorter codes that reference dictionary entries instead of the raw bytes. Unlike gzip‘s DEFLATE algorithm (which combines LZ77 with Huffman coding), classic LZW as implemented in compress doesn’t require storing an explicit Huffman table — the dictionary itself is rebuilt identically by the decompressor as it reads codes, since both sides follow the same deterministic rule for adding new dictionary entries.
This is elegant, but it historically caused real controversy: the LZW algorithm was covered by a Unisys patent, and disputes over licensing were part of why the free software community pushed hard to develop gzip (based on the patent-unencumbered DEFLATE algorithm) as a replacement in the late 1980s and early 1990s. That patent has long since expired, but .Z/LZW was effectively supplanted by .gz for that reason, plus the fact that DEFLATE also happens to compress better in most cases.
.Z files carry a fixed two-byte magic number (0x1F 0x9D) at the start, which is how tools identify them as LZW-compressed regardless of file extension.
Real-World Use Cases
Extracting legacy Unix software distributions. Old System V or BSD-era tar archives are sometimes distributed as .tar.Z. To fully extract one:
uncompress -c oldarchive.tar.Z | tar -xvf -
Reading old system logs or backups. Some ancient backup scripts (particularly from Solaris and older HP-UX systems) still default to compress rather than gzip. If you inherit infrastructure with a long history, you might find rotated logs ending in .Z.
Batch decompressing multiple .Z files at once:
uncompress *.Z
Piping through zcat instead, which I actually prefer for read-only inspection since zcat never touches the original file:
zcat oldfile.Z | less
uncompress vs gunzip vs unxz vs unzstd
This is where things get interesting because of overlapping tool support:
- uncompress only understands the LZW
.Zformat. - gunzip natively understands
.gzfiles but, on GNU systems, is also built to transparently decompress.Zfiles — a compatibility feature baked in specifically because.Zpredates.gz. - unxz and unzstd handle the modern
.xzand.zstdformats respectively, which offer substantially better compression ratios and speed, especiallyzstd, which has become the preferred choice for many modern backup and container image tools due to its excellent speed/ratio tradeoff.
In practice, if I find a .Z file today, I’ll usually just run gunzip file.Z rather than installing ncompress — unless I specifically need to also re-compress something back into .Z format for compatibility with an old system, in which case I need the real compress binary.
Troubleshooting Common Problems
“uncompress: command not found” — many minimal Docker images and modern distributions don’t include ncompress by default anymore, since .Z files are so rare. Install it:
# Debian/Ubuntu
sudo apt-get install ncompress
# RHEL/CentOS/Fedora
sudo yum install ncompress
# or
sudo dnf install ncompress
“Not in compressed format” — you’re trying to decompress a file that isn’t actually LZW-compressed, often because someone renamed a .gz or .bz2 file to .Z by mistake. Check the actual format with file filename.Z.
Permission denied writing output — uncompress needs write access to the directory containing the .Z file, since by default it writes the decompressed file alongside it and removes the original. Use -c combined with output redirection to a directory you do have write access to if the original directory is read-only.
Performance Considerations
LZW decompression is CPU-cheap and was specifically designed to be fast on the limited hardware of its era, so you’ll rarely see performance problems decompressing .Z files even on modest hardware — the files you’ll encounter are also almost always small by modern standards. Where performance actually matters is on the compression side, and this is precisely why the format fell out of favor: compress produces noticeably worse compression ratios than gzip -9, let alone xz or zstd, so there’s no reason to choose .Z for new projects.
Security Implications
There’s nothing inherently insecure about the LZW algorithm itself, but as with any decompression utility, you should be cautious about decompressing files from untrusted sources — malformed or maliciously crafted compressed streams have historically been used to trigger buffer handling bugs in various compression tools across the ecosystem. Since ncompress is a fairly minimal, rarely-audited legacy tool by 2020s standards, I avoid feeding it untrusted input directly and would rather convert suspicious .Z files in an isolated environment first.
Compatibility Across Distributions
ncompress (providing both compress and uncompress) is available in the default repositories of Debian, Ubuntu, RHEL/CentOS/Fedora, openSUSE, and Arch (via the ncompress AUR/community package depending on version), so installing it is consistent everywhere. gunzip‘s ability to also read .Z files is a GNU gzip feature and is present anywhere GNU gzip ships, which is effectively every mainstream Linux distribution.
Verifying a .Z File Before Trusting It
Since .Z files are uncommon enough today that mislabeling happens more often than with .gz, I always verify the actual format before committing to a decompression step in a script:
$ file compresstest.txt.Z
compresstest.txt.Z: compress'd data 16 bits
The file command reads the same magic number (1f 9d) that uncompress itself checks, so if file reports something other than “compress’d data,” you know immediately that uncompress will fail or, worse, silently misinterpret the input.
Combining uncompress With Other Tools in a Pipeline
Because uncompress -c writes to stdout, it composes naturally with the rest of a Unix pipeline exactly like zcat does for .gz files:
uncompress -c oldreport.txt.Z | grep "TOTAL" | awk '{print $2}'
I’ve used exactly this kind of one-liner when auditing old financial or scientific data exports stored in .Z format from systems that predate modern compression tooling, without needing to fully decompress the files to disk first.
Recompressing .Z Archives Into Modern Formats
If you’re modernizing a legacy data store and want to migrate away from .Z entirely while preserving the underlying data, a batch conversion script handles this cleanly:
#!/bin/bash
for f in *.Z; do
base="${f%.Z}"
uncompress -c "$f" | zstd -19 -o "${base}.zst"
done
This decompresses each .Z file on the fly and recompresses it directly into the modern, much more efficient zstd format, without ever needing a fully decompressed intermediate file sitting on disk — useful when migrating large historical archives where disk space is at a premium during the conversion process itself.
When You Might Still Choose .Z Deliberately
It’s rare, but I’ve encountered exactly one legitimate modern reason to produce .Z output deliberately: interoperating with an embedded or industrial control system running an old, frozen Unix-like OS image that only ships compress/uncompress and has no gzip available at all, often due to a vendor never updating the firmware. In that narrow case, compress/uncompress remain the only viable shared format between the two systems, which is exactly the kind of situation where understanding legacy tools thoroughly, rather than assuming everything modern has fully replaced them, actually pays off in practice.
A Closer Look at the LZW Dictionary Growth Process
To really understand why .Z files sometimes decompress slightly slower on very old hardware assumptions baked into the format, it helps to walk through what happens as the LZW dictionary grows during decompression. The decoder starts with the base 256-entry dictionary (one for each possible byte value), and every time it decodes a new code, it also adds a new entry to its dictionary — the previous output sequence plus the first byte of the current one. As the dictionary grows past 512, 1024, 2048 entries and so on, the number of bits needed to represent a code increases correspondingly (9 bits, then 10, then 11…), up to the maximum code width recorded in the file’s header (commonly 16 bits in modern ncompress output). This progressive widening is entirely automatic and transparent to the user, but it’s part of why -b exists as a tunable — capping the maximum code width trades away some compression ratio in exchange for a smaller, more constrained dictionary, which mattered enormously on 1980s hardware with limited memory and is essentially irrelevant today.
Handling Mixed Archives With Both .Z and .gz Members
Occasionally you’ll inherit a directory where some files were compressed with compress and others with gzip, often because different tools or different eras contributed to the same archive location over time. A safe batch-processing script needs to check each file’s actual format rather than assuming based on extension alone:
#!/bin/bash
for f in *.Z *.gz; do
[ -e "$f" ] || continue
case "$(file -b "$f")" in
*"compress'd data"*) uncompress -c "$f" > "${f%.*}.txt" ;;
*gzip*) zcat "$f" > "${f%.*}.txt" ;;
*) echo "Unknown format: $f" >&2 ;;
esac
done
I’ve used almost exactly this pattern when consolidating old backup directories inherited from a previous administrator, where trusting file extensions alone would have silently produced wrong results for a handful of mislabeled files.
Summary
uncompress is a small, largely historical tool these days, but it’s the key to unlocking .Z files whenever you come across one in an old archive or legacy system. Its LZW-based approach was the standard before gzip took over, and understanding why that transition happened — patent concerns plus better compression ratios — gives useful context for why the Unix compression landscape looks the way it does today. When you don’t have ncompress installed, remember gunzip can usually do the job just as well.
References
- GNU Gzip manual (covers
.Zcompatibility): https://www.gnu.org/software/gzip/manual/gzip.html man uncompress/man compress- ncompress project source: available via distribution package repositories
- Historical background on LZW and the Unisys patent dispute, referenced in the GNU Gzip project history