Compare Gzip Files Safely with zdiff and zcmp
Someone sends you a gzip archive and asks if it matches the report on disk, and zdiff answers that without you unpacking anything by hand. Use zdiff when you want a readable line-by-line difference, or zcmp when you want the compact byte-comparison behaviour of cmp. Both commands leave their input files alone. This guide describes gzip 1.12, installed here as package version 1.12-1ubuntu3.2.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a shell, the gzip package, and read access to the files you are comparing. The examples are ordinary user commands: they do not need sudo.
1. Check the installed commands
Confirm which executables your shell will run and record the version before relying on behaviour in a script:
$ command -v zdiff zcmp gzip
/usr/bin/zdiff
/usr/bin/zcmp
/usr/bin/gzip
$ zdiff --version
zdiff (gzip) 1.12
The commands are supplied by gzip. The zdiff and zcmp manual pages have the same synopsis: options are passed to the underlying diff or cmp program. The output style belongs to those standard comparison tools, while gzip handles decompression first.
Checkpoint
If command -v finds nothing, stop and install the gzip package through your normal package-management process. Do not copy a replacement executable into a system directory.
2. Compare a compressed file with its plain peer
With one argument, the command expects a compressed file and compares it with the corresponding uncompressed file. For report.txt.gz, the implicit peer is report.txt:
$ zdiff /path/to/report.txt.gz
$ printf '%s\n' "$?"
0
No output means diff found no differences. The compressed file is read, its contents are compared with the plain peer, and neither input is modified. The same one-file form with zcmp compares the contents using cmp:
$ zcmp /path/to/report.txt.gz
$ printf '%s\n' "$?"
0
Direction matters here. Running zdiff /path/to/report.txt does not automatically select report.txt.gz on this installed version; it reports an unknown compressed file extension, because the argument itself is not a recognised compressed input. Pass the .gz path when using the one-file form.
3. Compare two files, including mixed compression
With two arguments, each input is decompressed if necessary before it is passed to the comparison program. This lets you compare a gzip archive with a plain working copy:
$ zdiff /path/to/old-report.txt.gz /path/to/new-report.txt
2c2
< beta
---
> gamma
$ printf '%s\n' "$?"
1
Your line number and text will differ. What matters is the status:
- 0 means equal. The inputs compare the same once decompressed.
- 1 means different.
difffound a real difference; that is a successful comparison, not an error. - 2 normally means trouble. A missing file or an unreadable input, so do not treat every non-zero result as an ordinary content change.
Checkpoint
Test the status immediately after the comparison. Any command inserted between zdiff and printf replaces the status you are trying to inspect.
4. Choose readable output or a compact comparison
Use zdiff for reports, source files and configuration snapshots where changed lines need to be understood. It passes comparison options to diff, so a unified view is available:
$ zdiff -u /path/to/old-report.txt.gz /path/to/new-report.txt.gz
--- /dev/fd/...
+++ /dev/fd/...
@@ -1,2 +1,2 @@
alpha
-beta
+gamma
The temporary-looking names in the headers are a known limitation of the wrapper: the manual warns that messages from diff or cmp can refer to names such as - instead of the paths you supplied. Read the hunks and exit status rather than building automation around those labels.
Use zcmp when you only need equal or different, or when the first differing byte is useful:
$ zcmp /path/to/old-report.txt.gz /path/to/new-report.txt.gz
/dev/fd/5 - differ: byte 7, line 2
$ printf '%s\n' "$?"
1
Options such as -l and -s belong to cmp, and options such as -u belong to diff. Check man cmp or man diff for the option you intend to pass. Do not assume an option is interpreted by gzip itself.
5. Put the result in a shell check
Keep the three useful outcomes distinct. This example prints a short message while preserving a failure caused by a missing or unreadable file:
if zdiff -q /path/to/old-report.txt.gz /path/to/new-report.txt.gz; then
printf '%s\n' 'files are identical'
else
status=$?
case "$status" in
1) printf '%s\n' 'files differ' ;;
*) printf 'comparison failed with status %s\n' "$status" >&2; exit "$status" ;;
esac
fi
Here -q is passed to diff and suppresses its normal difference report. If you need a report for a human, remove -q and keep the same status handling. The command still does not alter either input.
Common traps
- Wrong direction on the one-file form. Give
zdiffthe.gzpath, not the plain one; it will not guess the compressed peer from a plain filename. - An unknown extension error. Check the argument rather than renaming files blindly. The wrapper recognises gzip input by its compressed filename extension. If a gzip file has a different name, give it a temporary name ending in
.gzor decompress it through a separate, deliberate workflow. - Comparing metadata by accident. gzip compression metadata is not the subject of this comparison.
zdiffandzcmpcompare the uncompressed contents, so two gzip files with different headers can still compare equal here if their decompressed data is the same. - Swallowed exit status. Do not pipe comparison output into a command that hides the exit status unless you deliberately capture it.
First check that each named path exists and is readable, before assuming a comparison failure is a content problem:
$ ls -l /path/to/old-report.txt.gz /path/to/new-report.txt
$ test -r /path/to/old-report.txt.gz && echo 'old input readable'
$ test -r /path/to/new-report.txt && echo 'new input readable'
There is no destructive operation to undo here. If a comparison fails, leave the inputs in place and correct the path, permissions or expected peer. Elevated privileges are not a normal fix; use them only under your organisation's access policy when the files genuinely require privileged reading.
Done means
- zdiff gives a readable difference and zcmp gives compact comparison output when needed.
- Compressed, plain and mixed input pairs have been compared without editing either file.
- Status 0 means equal, status 1 means different, and other statuses are investigated as errors.
- The one-file form is given the
.gzpath whose plain peer it should find. - Shell automation checks the exit status immediately and does not confuse a missing input with changed content.