Compare Compressed Files Safely with xzdiff and xzcmp
By the end of this guide you will be able to compare compressed files directly, compare a compressed file with its uncompressed sibling, and use the exit status in a script without mistaking a real difference for a command failure. No input file is changed and no elevated privileges are needed.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about 10 minutes. You need XZ Utils, a shell, and two files you are allowed to read. The examples use paths such as /path/to/first.log.xz; replace them with real paths before running a command.
1. Check which XZ Utils you are using
First confirm that the command is installed and record its version. This matters when a machine has more than one XZ Utils installation on PATH.
$ command -v xzdiff
$ /usr/bin/xz --version | head -2
On the machine used for this guide, the distribution package is xz-utils 5.6.1+really5.4.5-1ubuntu0.3, and /usr/bin/xz reports XZ Utils 5.4.5. The installed man page is dated 2021-06-04. If command -v points somewhere else, use that installation consistently when checking behaviour.
Checkpoint
command -v xzdiff prints a real executable path and xz --version prints a version.
2. Compare two compressed files as text
Use xzdiff when you want normal diff output. It decompresses supported inputs as needed and feeds their contents to diff. It does not replace either file.
$ xzdiff /path/to/first.log.xz /path/to/second.log.xz
For identical content, the command prints nothing and exits with status 0. For different content, it prints a normal diff and exits with status 1. For example, a changed second line can look like this:
2c2
< beta
---
> gamma
Capture the status immediately if a script needs it:
if xzdiff /path/to/first.log.xz /path/to/second.log.xz > /tmp/log-diff.txt; then
printf '%s\n' 'files have identical content'
else
status=$?
if [ "$status" -eq 1 ]; then
printf '%s\n' 'files differ'
else
printf 'comparison failed with status %s\n' "$status" >&2
exit "$status"
fi
fi
The redirection saves the diff while leaving the source files untouched. Choose a private temporary path appropriate to your environment if the compared content is sensitive.
3. Compare bytes with xzcmp
Use xzcmp when you need cmp semantics rather than line-oriented diff output. It accepts the same compressed input handling but reports the first byte position that differs.
$ xzcmp /path/to/first.bin.xz /path/to/second.bin.xz
+/dev/fd/5 - differ: byte 7, line 2
Like cmp, status 0 means identical and status 1 means different. A decompression error is reported with status 2 by the XZ Utils wrapper. Do not use xzcmp output as a patch: it is a comparison result, not a reversible change operation.
4. Use the one-file form carefully
With one argument, xzdiff removes the recognised compression suffix from that argument and compares the result with the file that remains. This is useful when both forms are deliberately kept together.
$ ls -l /var/tmp/report.txt /var/tmp/report.txt.xz
$ xzdiff /var/tmp/report.txt.xz
Here the command compares report.txt.xz with report.txt. The uncompressed sibling must already exist. The command does not create it for you, and it does not infer a different filename from the contents.
The recognised formats in the local man page are .xz, .lzma, .gz, .bz2, .lzo, and .zst. A suffix outside that set will not give the one-file form the filename you expect. Use two explicit filenames when in doubt.
Checkpoint
Run xzdiff with two explicit paths first. If the one-file form behaves unexpectedly, inspect both exact filenames with ls -l.
5. Pass comparison options, not decompression options
Options are passed directly to diff or cmp. For instance, -q asks diff for a brief result.
$ xzdiff -q /path/to/first.txt.xz /path/to/second.txt.xz
Files /dev/fd/5 and /dev/fd/6 differ
Use the option spelling supported by the underlying comparison program installed on your system. The wrapper does not document a separate set of decompression switches. If a filename begins with a hyphen, use a path such as ./-old.log.xz rather than assuming an option terminator will be interpreted identically by every wrapper version.
6. Diagnose failures without changing the inputs
A difference is not the same as an error. Check the status and then check the files and tools when the status is 2 or another unexpected value.
$ test -r /path/to/first.log.xz && test -r /path/to/second.log.xz
$ file /path/to/first.log.xz /path/to/second.log.xz
$ xz --test /path/to/first.log.xz
$ echo "$?"
xz --test checks an XZ stream; it is not a general test for every format that xzdiff can dispatch. A malformed or truncated compressed file can produce a decompression diagnostic, and the wrapper documents status 2 for that case. Permission errors, missing files, and unsupported formats should be read alongside the command's diagnostic rather than treated as proof that the files differ.
Diagnostics from diff and cmp can mention temporary file names instead of the paths you supplied. That is a documented quirk of this wrapper. Compare the exit status and the content of the report, not the temporary names.
7. Remember the aliases
xzdiff and xzcmp are the descriptive names. lzdiff and lzcmp are provided for LZMA Utils compatibility, and follow the same documented forms. Prefer the XZ names in new scripts so that the purpose is clear.
Neither command requires sudo. They read inputs, may invoke the relevant decompressor, create temporary comparison streams, and return the underlying comparison status. They do not modify the compared files. Avoid putting secrets in a diff report or a shared temporary directory, because differing content may be written there or displayed on screen.
Done means
xzdiffcompares text content and its status is handled as 0 identical, 1 different, or 2 decompression failure.xzcmpis used when byte-oriented comparison output is the right fit.- The one-file form is used only when the uncompressed sibling and its stripped compression suffix are known.
- No source file was overwritten, and any saved diff was written to an intentional path.