bzdiff Command in Linux with Examples

Use the bzdiff command in Linux to compare .bz2 files, read diff output, handle exit codes, ignore noise, and fix common errors.

PublishedAuthorJoshua JamesRead time8 minGuide typeLinux Commands

Comparing old log snapshots or configuration exports gets awkward when the files are still compressed with bzip2. The bzdiff command in Linux compares the decompressed content of .bz2 files without making you unpack them by hand, so you can keep archived files in place while checking exactly what changed.

bzdiff is a wrapper around diff from the bzip2 package. It is useful for text-like compressed files such as rotated logs, config snapshots, SQL exports, and release notes. It compares content after decompression, not the compressed bytes on disk, so checksum and byte-for-byte archive checks still belong to tools such as cmp or sha256sum.

Use bzdiff Command Syntax and Common Patterns

bzdiff invokes diff against bzip2-compressed input. It decompresses one or both files for comparison, passes supported diff options through, and returns the same meaningful exit statuses that diff uses.

bzdiff [diff_options] file1 [file2]
  • [diff_options]: Options passed to diff, such as -u for unified output, -q for quiet comparison, or -w to ignore whitespace.
  • file1: The first file, normally a .bz2 file.
  • [file2]: The second file. If omitted, bzdiff compares file1 with the matching uncompressed filename when that file exists.

The official bzip2 manual documents the bzip2 utility family. For quick use, these patterns cover the most common bzdiff workflows:

TaskCommand PatternWhat It Does
Compare two bzip2 filesbzdiff old.txt.bz2 new.txt.bz2Prints normal diff output after decompression.
Show unified outputbzdiff -u --label=old.txt --label=new.txt old.txt.bz2 new.txt.bz2Uses unified diff format with stable labels.
Check quietlybzdiff -q old.txt.bz2 new.txt.bz2Returns a status code without printing the full diff.
Use the matching plain filebzdiff old.txt.bz2Compares old.txt.bz2 with old.txt when the plain file exists.
Show side-by-side changesbzdiff -y --suppress-common-lines --width=120 old.txt.bz2 new.txt.bz2Shows changed lines in two columns.
Save a reportbzdiff -u old.txt.bz2 new.txt.bz2 > changes.diffWrites a patch-style report while preserving bzdiff status codes.
Ignore whitespace and blanksbzdiff -w -B old.txt.bz2 new.txt.bz2Ignores spacing-only and blank-line-only changes.
Ignore matching linesbzdiff -I'^#' old.txt.bz2 new.txt.bz2Ignores changed hunks made only of matching comment lines.
Compare compressed with plain textbzdiff old.txt.bz2 old.txtCompares a compressed file with an uncompressed copy.
Compare decompressed bytes quietlybzcmp -s old.txt.bz2 copy.txt.bz2Uses the companion bzcmp wrapper for byte-stream equality.

When a diff option takes a value, use an equals or joined form with bzdiff, such as --label=old.txt or -I'^#'. A separated value can be interpreted as a filename by the wrapper.

Install or Verify bzdiff on Linux

The bzip2 package provides bzdiff, bzcmp, bzcat, bunzip2, and related helpers. Many desktop installations already include it, while minimal servers and containers may need the package installed first.

Check whether the command is already available:

command -v bzdiff

A common command path is:

/usr/bin/bzdiff

If the command is missing, install the bzip2 package for your distribution.

Ubuntu and Debian-Based Distributions

sudo apt update
sudo apt install bzip2

Fedora and RHEL-Family Distributions

sudo dnf install bzip2

Arch Linux and Manjaro

sudo pacman -S bzip2

openSUSE Tumbleweed

sudo zypper install bzip2

On openSUSE Leap, search your enabled repositories before adding community or experimental package sources for this small utility.

After installation, repeat command -v bzdiff. If it still returns nothing, open a new shell and check that /usr/bin is present in $PATH.

Create a Disposable bzdiff Practice Directory

A small practice directory keeps the examples safe and repeatable. Create two similar text files, preserve an identical copy, then compress all three with bzip2 -k. The -k option keeps the original uncompressed files so later examples can compare compressed and plain-text content.

mkdir -p ~/bzdiff-demo
cd ~/bzdiff-demo
cat > old.txt <<'EOF'
port=8080
mode=production
cache=true
EOF
cat > new.txt <<'EOF'
port=8080
mode=staging
cache=true
EOF
cp old.txt old-copy.txt
rm -f -- old.txt.bz2 new.txt.bz2 old-copy.txt.bz2
bzip2 -k old.txt new.txt old-copy.txt
ls -1 *.bz2

The directory now contains three compressed files:

new.txt.bz2
old-copy.txt.bz2
old.txt.bz2

Compare bzip2 Files with bzdiff

Start with the plain comparison form when you want compact output and do not need script-friendly labels.

Compare Two Compressed Text Files

Compare the two compressed config snapshots:

bzdiff old.txt.bz2 new.txt.bz2

The output uses normal diff notation. The change marker shows line 2 moving from production to staging:

2c2
< mode=production
---
> mode=staging

A difference returns exit status 1. That status means the files differ; it is not the same as a broken command.

Show Unified Diff Output with Stable Labels

Use unified output when the result needs to fit review comments, patches, or readable change logs. Add labels with equals-style --label=VALUE options so the wrapper passes each label to diff correctly:

bzdiff -u --label=old.txt --label=new.txt old.txt.bz2 new.txt.bz2
--- old.txt
+++ new.txt
@@ -1,3 +1,3 @@
 port=8080
-mode=production
+mode=staging
 cache=true

Without labels, unified output can show temporary paths created by the wrapper. Labels keep the output stable and easier to paste into tickets or code reviews.

Compare a Compressed File with Plain Text

bzdiff can compare a compressed file with an uncompressed file. This is useful after extracting or editing a local copy:

bzdiff -q old.txt.bz2 old.txt && echo "Compressed and uncompressed contents match"
Compressed and uncompressed contents match

The -q option keeps the comparison quiet when the files match. Remove -q when you want the full diff.

Compare a Compressed File with Its Matching Plain File

When the second file is omitted, bzdiff compares the compressed file with the matching uncompressed name. With old.txt.bz2, the implicit comparison target is old.txt:

bzdiff -q old.txt.bz2 && echo "Compressed file matches old.txt"
Compressed file matches old.txt

This shortcut is convenient after bzip2 -k, because the original file stays beside the compressed copy. If the plain file is missing, diff returns a real error instead of silently comparing against nothing.

Show Side-by-Side bzdiff Output

Side-by-side output is easier to scan when only a few lines changed. Use joined or equals-style values for options that take arguments, such as --width=72:

bzdiff -y --suppress-common-lines --width=72 old.txt.bz2 new.txt.bz2

Relevant output keeps the unchanged lines hidden and shows the changed setting in two columns:

mode=production                           | mode=staging

Use a larger --width value for long configuration lines. If the output wraps in your terminal, redirect the report to a file or switch back to unified output with -u.

Save a bzdiff Report to a File

Saving a unified report is useful for tickets, backup audits, and deployment notes. Capture the status separately because a saved diff still exits with status 1 when differences exist:

bzdiff -u --label=old.txt --label=new.txt old.txt.bz2 new.txt.bz2 > config.diff
status=$?
if [ "$status" -eq 1 ]; then
    echo "Saved differences to config.diff"
elif [ "$status" -ne 0 ]; then
    echo "bzdiff failed with status $status" >&2
fi
Saved differences to config.diff

Inspect the report with less config.diff or attach it to a change record. Avoid chaining the redirect with && when changed content is a normal result.

Check bzdiff Exit Status in Scripts

Scripts need to treat status 1 as a real comparison result. Capture the status and branch on it instead of assuming any nonzero status is fatal:

if bzdiff -q old.txt.bz2 new.txt.bz2 >/dev/null; then
    echo "No differences"
else
    status=$?
    if [ "$status" -eq 1 ]; then
        echo "Files differ"
    else
        echo "bzdiff failed with status $status" >&2
    fi
fi
Files differ

Use this pattern in backup audits or deployment checks where changed content should trigger a report, while missing files or corrupt input should fail the job.

Ignore Whitespace and Blank-Line Changes

diff -w ignores whitespace while comparing lines, and -B ignores changes that are only blank lines. Both options work through bzdiff:

cat > spaces-a.txt <<'EOF'
key=value

path=/srv/app
EOF
cat > spaces-b.txt <<'EOF'
key = value
path = /srv/app
EOF
rm -f -- spaces-a.txt.bz2 spaces-b.txt.bz2
bzip2 -k spaces-a.txt spaces-b.txt
bzdiff -w -B -q spaces-a.txt.bz2 spaces-b.txt.bz2 && echo "Only whitespace or blank lines changed"
Only whitespace or blank lines changed

This is useful for generated configuration files where formatting changed but the meaningful key/value data did not. Do not use these options when indentation or blank lines carry meaning for the file format you are reviewing.

Ignore Generated Comment Lines

Use -I when every changed line in a hunk matches a pattern, such as generated timestamp comments. Keep the pattern joined to -I so the wrapper does not treat it as a filename:

cat > comments-a.txt <<'EOF'
# generated=100
port=8080
mode=production
EOF
cat > comments-b.txt <<'EOF'
# generated=200
port=8080
mode=production
EOF
rm -f -- comments-a.txt.bz2 comments-b.txt.bz2
bzip2 -k comments-a.txt comments-b.txt
bzdiff -q -I'^#' comments-a.txt.bz2 comments-b.txt.bz2 && echo "Only generated comments changed"
Only generated comments changed

Use this only when comment-only differences are safe to ignore. If a hunk includes both a comment and a real setting change, diff -I still reports the hunk.

Compare Matching Compressed Files Across Directories

bzdiff expects regular files, so it does not recurse through directories like diff -r. For compressed snapshot folders, build a controlled file list and compare matching relative paths:

mkdir -p old-set/app new-set/app
printf 'alpha\n' > old-set/app/same.conf
printf 'alpha\n' > new-set/app/same.conf
printf 'mode=prod\n' > old-set/app/changed.conf
printf 'mode=stage\n' > new-set/app/changed.conf
printf 'only-old\n' > old-set/app/missing.conf
find old-set new-set -type f -name '*.bz2' -delete
find old-set new-set -type f -name '*.conf' -exec bzip2 -k {} \;

find old-set -type f -name '*.bz2' | sort | while IFS= read -r old_path; do
    rel=${old_path#old-set/}
    new_path="new-set/$rel"
    if [ ! -f "$new_path" ]; then
        printf 'MISSING %s\n' "$rel"
        continue
    fi

    bzdiff -q "$old_path" "$new_path" >/dev/null
    status=$?
    case "$status" in
        0) printf 'SAME %s\n' "$rel" ;;
        1) printf 'DIFF %s\n' "$rel" ;;
        *) printf 'ERROR %s status=%s\n' "$rel" "$status" ;;
    esac
done
DIFF app/changed.conf.bz2
MISSING app/missing.conf.bz2
SAME app/same.conf.bz2

This pattern is safer than running a broad comparison over every file in both trees because it names missing files separately and keeps status 1 as a normal difference result.

Compare Filtered Content from bzip2 Logs

bzdiff compares the whole decompressed file. Use Bash process substitution with bzcat when you need to filter output with grep before comparing only matching lines:

cat > old.log <<'EOF'
INFO startup
ERROR cache stale
INFO done
EOF
cat > new.log <<'EOF'
INFO startup
ERROR cache refreshed
INFO done
EOF
rm -f -- old.log.bz2 new.log.bz2
bzip2 -k old.log new.log

diff -u --label=old-errors --label=new-errors \
    <(bzcat old.log.bz2 | grep '^ERROR') \
    <(bzcat new.log.bz2 | grep '^ERROR')
--- old-errors
+++ new-errors
@@ -1 +1 @@
-ERROR cache stale
+ERROR cache refreshed

This is no longer a pure bzdiff command, but it solves a common compressed-log problem without unpacking either file. Use it in Bash; plain POSIX sh does not support process substitution.

Use bzcmp for Quiet Byte-Stream Checks

The companion bzcmp command compares decompressed byte streams through cmp. It is a better fit when you only need equality and not line-oriented diff output:

bzcmp -s old.txt.bz2 old-copy.txt.bz2 && echo "Decompressed byte streams match"
Decompressed byte streams match

Compare Content Instead of Compressed Bytes

bzdiff answers a content question: do these files decompress to the same text? It does not prove the compressed archives are byte-for-byte identical. Compression settings can create different .bz2 files from the same input.

cp old.txt same-low.txt
cp old.txt same-high.txt
rm -f -- same-low.txt.bz2 same-high.txt.bz2
bzip2 -1 -k same-low.txt
bzip2 -9 -k same-high.txt

cmp -s same-low.txt.bz2 same-high.txt.bz2 || echo "Compressed files differ"
bzdiff -q same-low.txt.bz2 same-high.txt.bz2 && echo "Decompressed contents match"
Compressed files differ
Decompressed contents match

Use bzdiff for content review. Use cmp or sha256sum when transfer integrity, cache identity, or exact archive bytes matter.

Use the Right Tool for Other Archive Formats

bzdiff is specific to bzip2 streams. If a file uses .gz, .tgz, or .tar.gz, use gzip and tar workflows instead; the GZ and TGZ extraction guide explains those formats. ZIP archives are a separate container format, so use unzip command examples when the file ends in .zip.

A .tar.bz2 file is a tar archive compressed as one bzip2 stream. The same boundary applies to shorthand names such as .tbz2 and .tbz. bzdiff can tell you some tar streams differ, but it does not compare archive members by filename. List the archive first when you only need to confirm what it contains:

tar -tjf old-backup.tar.bz2

For member-by-member review, extract both archives into empty disposable directories, then compare those directories with normal diff:

mkdir -p old-backup new-backup
tar -xjf old-backup.tar.bz2 -C old-backup
tar -xjf new-backup.tar.bz2 -C new-backup
diff -ru old-backup new-backup

When you are unsure about a file, inspect it before choosing a comparison tool:

file old.txt.bz2
old.txt.bz2: bzip2 compressed data, block size = 900k

A bzip2 file reports bzip2-compressed data. A misleading extension is a common reason bzdiff fails before it reaches diff.

Troubleshoot Common bzdiff Errors

Most bzdiff failures come from command availability, wrapper argument parsing, regular-file limits, invalid bzip2 data, or scripts that treat a normal difference status as fatal.

Fix bzdiff Command Not Found

If your shell cannot find bzdiff, check the command path first:

command -v bzdiff || echo "bzdiff is missing"

Install bzip2 with your distro package manager, then repeat the check. The package name is bzip2, not bzdiff.

Fix Option Values Treated as Filenames

A separated option value can make bzdiff stop before it compares the intended files. For example, this form passes ^# as a separate argument:

bzdiff -q -I '^#' comments-a.txt.bz2 comments-b.txt.bz2
bzdiff: ^# not found or not a regular file

Attach the value to the option, or use an equals form when the long option supports one:

bzdiff -q -I'^#' comments-a.txt.bz2 comments-b.txt.bz2
bzdiff -u --label=old.txt --label=new.txt old.txt.bz2 new.txt.bz2

Fix Missing Plain File Errors

The one-file form depends on the matching uncompressed file. If old.txt is missing, bzdiff old.txt.bz2 reaches diff and fails:

rm -f old.txt
bzdiff -q old.txt.bz2
diff: old.txt: No such file or directory

Restore the plain file when you want to compare the compressed copy against its original name:

bunzip2 -k old.txt.bz2
bzdiff -q old.txt.bz2 && echo "Compressed file matches old.txt"
Compressed file matches old.txt

If you meant to compare against a different file, give that second filename explicitly instead of relying on the one-file shortcut.

Fix Directory Arguments Not Regular File

bzdiff does not recurse through directories. Passing directory names, even with a normal diff option such as -r, stops at the wrapper:

bzdiff -r old-set new-set
bzdiff: old-set not found or not a regular file

Compare directory snapshots by iterating over regular .bz2 files and matching relative paths. A safe loop should report same, different, missing, and error states separately.

Fix Usage Output with Filenames That Contain Spaces

Some packaged bzdiff wrappers split the file list internally, so shell quoting does not reliably save pathnames with spaces. A quoted command can still collapse to a usage error:

printf 'left\n' > 'old space.txt'
printf 'right\n' > 'new space.txt'
rm -f -- 'old space.txt.bz2' 'new space.txt.bz2'
bzip2 -k 'old space.txt' 'new space.txt'
bzdiff 'old space.txt.bz2' 'new space.txt.bz2'
Usage: bzdiff [diff_options] file [file]

Use diff with bzcat in Bash when you must compare files with spaces in their names:

diff -u --label="old space.txt" --label="new space.txt" \
    <(bzcat "old space.txt.bz2") \
    <(bzcat "new space.txt.bz2")
--- old space.txt
+++ new space.txt
@@ -1 +1 @@
-left
+right

That fallback also works for generated streams, but it uses Bash process substitution. For portable shell scripts, decompress into a temporary directory with safe filenames, compare those files, and remove the temporary directory afterward.

Fix Bad Magic Number Errors

A file with a .bz2 extension is not necessarily valid bzip2 data. Test the archive before comparing it:

printf 'not bzip2 data\n' > bad.bz2
bzip2 -t bad.bz2
bzip2: bad.bz2: bad magic number (file not created by bzip2)

You can use the `bzip2recover' program to attempt to recover
data from undamaged sections of corrupted files.

Use the correct file or retrieve a fresh copy. If the file is a damaged bzip2 archive and you must salvage partial data, run bzip2recover in a clean directory and inspect the recovered pieces before trusting them.

Fix Scripts That Fail on Real Differences

Automation often runs with set -e, which exits on any nonzero status. Since bzdiff returns 1 for normal differences, wrap the command in an if statement or capture the status before the shell exits.

Use this interpretation when debugging a script: status 0 means no differences, status 1 means differences were found, and status 2 or another higher value means a real comparison problem such as a missing file, invalid archive, or unsupported option form.

Clean Up the bzdiff Demo Directory

Remove only the practice directory created for these examples when you no longer need the compressed fixtures:

cd ~
rm -rf ~/bzdiff-demo

Conclusion

bzdiff is ready for compressed-content reviews when you can compare .bz2 files, save reports, filter inputs safely, handle exit status 1 correctly, and avoid wrapper traps around directories, option values, and filenames with spaces. Keep bzcmp for quiet byte-stream matches, and use tar or format-specific tools when the archive is not a plain bzip2 stream.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show our tutorials more often in Top Stories and mark them as preferred in AI Mode and AI Overviews when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<a href="https://example.com">link</a> link
<blockquote>quote</blockquote> quote block

Add to the discussion

Questions, fixes, command output, and version notes help keep this guide current.

Verify before posting: