Compress and Restore Files Safely with ncompress

compress and its counterpart uncompress.real still turn up wherever the old .Z format refuses to die. This covers making .Z files, restoring them, and streaming instead of touching a file in place. Examples use ncompress 5.0, installed here as package version 5.0-1.

Allow about fifteen minutes. You need the ncompress package and a shell; these commands work on ordinary files in a directory you control and never need elevated privileges. Do not test them against a system directory or an irreplaceable file until you have proven the workflow on a copy.

1. Check the installed commands

Debian installs the decompressor as uncompress.real so it does not clash with the more common uncompress that gzip supplies. Check both paths and the build details before relying on them in a script:

$ command -v compress
/usr/bin/compress
$ command -v uncompress.real
/usr/bin/uncompress.real
$ compress -V
Compress version: (N)compress 5.0
Compile options:
        FAST,
        IBUFSIZ=8192, OBUFSIZ=8192, BITS=16

The default maximum code width here is 16 bits. compress accepts a width from 9 to 16 with -b; the decompressor reads that value straight from the .Z file, so it has no matching option of its own.

Checkpoint: if command -v finds a different implementation, read its manual page before copying these results into automation.

2. Compress one file in place

$ yes 'the same line repeated for compression testing' | head -n 200 > sample.txt
$ compress -v sample.txt
sample.txt:  -- replaced with sample.txt.Z Compression: 88.00%

Without -c, a successful compression replaces sample.txt with sample.txt.Z, keeping ownership, mode and timestamps where possible. If the result would not be smaller, the input is left alone and the exit status is 2, not 0.

$ ls -l sample.txt.Z
-rw-r--r-- 1 you you 1128 ... sample.txt.Z
$ printf 'compress status: %s\n' "$?"
compress status: 0

That status is only meaningful right after the command it describes, so capture it immediately in a script:

compress -v -- sample.txt
status=$?
case "$status" in
    0) printf '%s\n' 'compressed' ;;
    2) printf '%s\n' 'no space saved; input was left alone' ;;
    *) printf 'compress failed with status %s\n' "$status" >&2; exit "$status" ;;
esac

3. Restore a .Z file

$ uncompress.real -v sample.txt.Z
sample.txt.Z:  -- replaced with sample.txt
$ printf 'uncompress status: %s\n' "$?"
uncompress status: 0
$ test -f sample.txt && test ! -e sample.txt.Z
$ printf 'restored: %s\n' "$?"
restored: 0

The decompressor checks both the .Z suffix and the file's magic number, so a random unrelated file gets rejected rather than treated as compressed data: a plain text file, for instance, produces not in compressed format and status 1.

Warning: normal operation removes the compressed input once the restored file exists. Keep an independent backup if the archive is your only copy. Used -k on either side already? Both files remain, and you can remove the unwanted one after checking its contents.

4. Keep the input and choose a smaller code width

$ compress -k keep.txt
$ ls -l keep.txt keep.txt.Z
-rw-r--r-- 1 you you 3200 ... keep.txt
-rw-r--r-- 1 you you  361 ... keep.txt.Z
$ uncompress.real -k keep.txt.Z
$ ls -l keep.txt keep.txt.Z

Warning: do not add -f casually. It allows overwriting an existing destination and lets compression proceed on files with multiple hard links, which can surprise another path pointing at the same inode. Without it, an interactive foreground run asks before replacing anything.

For compatibility with older machines with very small process data space, the manual recommends -b 12, used only when that requirement is real:

$ compress -b 12 -- archive.txt

The option affects compression only; it is not passed to uncompress.real.

5. Stream data without changing files

-c writes compressed or restored data to standard output and leaves named files alone, useful for a pipeline or a one-off transfer:

$ printf 'stream input\n' | compress -c | uncompress.real -c
stream input

A shell redirection opens its destination before the command runs, so never redirect back onto the same input file:

$ compress -c -- report.txt > report.txt.Z
$ uncompress.real -c -- report.txt.Z > restored-report.txt
$ cmp -- report.txt restored-report.txt
$ printf 'identical: %s\n' "$?"
identical: 0

Use -- to stop option parsing for a filename starting with a hyphen, and quote paths with spaces. A stream has no filename for ncompress to rename, so the redirection target is entirely your responsibility.

6. Compress a directory deliberately

compress only touches one named file by default; add -r to descend into named directories:

$ compress -r -- project-data
project-data/log.txt:  -- replaced with project-data/log.txt.Z Compression: 87.00%
$ uncompress.real -r -- project-data

Inspect the tree before and after each run. There is no single undo for a recursive operation; restoration only works for whichever .Z files still exist.

Done means