Home / Alt manpages / cmp(1)

  • cmp(1)
  • User command
  • linux

Compare Files Byte by Byte with cmp, Then Trust the Exit Status

cmp answers one question: are these two files identical, byte for byte? It stays silent on a match and points straight at the first differing byte and line otherwise, and that plain exit status is what makes it useful inside a script. Examples use GNU cmp from diffutils 3.10, installed as the diffutils package.

Allow about ten minutes. You need two readable files and an ordinary shell; nothing here needs elevated privileges.

Checkpoint

This guide only compares data, it never alters either input, so there is no rollback step and no reason to run any of it with sudo.

1. Check the installed command

Confirm which executable your shell will run and note its version: the options and diagnostics below are for GNU diffutils 3.10, and another implementation may differ.

$ command -v cmp
/usr/bin/cmp
$ cmp --version | head -n 1
cmp (GNU diffutils) 3.10

cmp compares raw bytes, not text lines or characters, so a changed newline, encoding or metadata byte is enough to make two apparently similar files count as different.

2. Test for equality without producing noise

Pass two file names. Identical inputs get silence and status 0; different inputs get the first differing byte and line, then status 1.

$ cmp /path/to/original.bin /path/to/copy.bin
$ printf 'cmp status: %s\n' "$?"
cmp status: 0

$ cmp /path/to/original.bin /path/to/suspect.bin
/path/to/original.bin /path/to/suspect.bin differ: byte 4097, line 1
$ printf 'cmp status: %s\n' "$?"
cmp status: 1
  • No news is good news. Silence plus status 0 is the successful equality case, not a hung command.
  • Numbers start at 1. Byte and line counts are 1-indexed.
  • Binary files still get a "line". A file with no real line structure can still report line 1 for a difference.

Checkpoint

Repeat the command against a known identical pair. You should see no output and an exit status of 0.

3. Read a first-difference diagnostic

For a human investigation, add --print-bytes to show the two differing byte values, or --verbose to list every one. Both still return 1 when a difference exists.

$ cmp --print-bytes /tmp/left.bin /tmp/right.bin
/tmp/left.bin /tmp/right.bin differ: byte 4, line 1 is 130 X 170 x
$ cmp --verbose /tmp/left.bin /tmp/right.bin
4 130 170

Verbose output is a stream of byte number, value from the first file, value from the second, all decimal. Use it for a complete list, but do not pipe a large one straight to a terminal; redirect it to a review file with a deliberate name instead. cmp will not explain a text change in words: reach for a line-oriented diff tool after this byte-level check if that is what you need.

4. Compare only a prefix or skip file headers

--bytes=LIMIT checks only the first LIMIT bytes; a match there returns 0 even if the files differ later, which is useful for a format signature or protocol header but is not a whole-file verification.

$ cmp --bytes=16 /path/to/header-a.bin /path/to/header-b.bin
$ printf 'header status: %s\n' "$?"
header status: 0

--ignore-initial=SKIP skips the same number of bytes in both inputs; the GNU form --ignore-initial=SKIP1:SKIP2 skips different lengths in each, and the equivalent positional operands work too: cmp FILE1 FILE2 SKIP1 SKIP2.

$ cmp --ignore-initial=512:1024 /path/to/left.img /path/to/right.img
$ printf 'payload status: %s\n' "$?"
payload status: 0

Warning

Check the format specification before choosing offsets. Skipping the wrong number of bytes can make unrelated data look equal, which is a verification error, not a harmless convenience. Size suffixes exist: K means 1024 while kB means 1000, and M/MB follow the same split.

5. Use standard input deliberately

A file name of - means standard input, so you can compare a file against a generated stream without saving it first. Remember a pipe is consumed once.

$ cmp /path/to/reference.txt - < /path/to/generated.txt
$ printf 'stream status: %s\n' "$?"
stream status: 0

Do not assume every shell preserves cmp's status through a longer pipeline: capture it immediately as shown, or use the shell's pipeline-status facility explicitly. Quote untrusted file names, especially ones starting with a hyphen; use a path like ./-input.bin when you have to.

6. Make scripts distinguish different from broken

Three statuses matter:

  • 0. The selected inputs matched.
  • 1. The selected inputs differed.
  • 2. cmp could not complete, for example a missing or unreadable file.
if cmp --quiet -- /path/to/expected.bin /path/to/actual.bin; then
    printf '%s\n' 'match'
else
    status=$?
    case "$status" in
        1) printf '%s\n' 'different' ;;
        2) printf 'comparison failed (status %s)\n' "$status" >&2; exit "$status" ;;
        *) printf 'unexpected cmp status %s\n' "$status" >&2; exit "$status" ;;
    esac
fi

--quiet suppresses normal comparison output, and -- marks the end of options. Test the error path with a deliberately wrong file if you are checking the script, then put the real path back. Never collapse status 1 into a generic failure without deciding whether "different" is actually an expected result for your workflow.

Done means

  • Version checked. The installed cmp is GNU diffutils 3.10, or you adjusted for your implementation.
  • Statuses understood. 0 is a match, 1 is a difference, 2 is trouble.
  • Offsets justified. Any --bytes or --ignore-initial use matches the file format.
  • Paths quoted. Standard input was treated as a one-use stream and every command stayed unprivileged.