kmail.at
contact

elsewhere

EnglishEN
← learning

linux · difficulty ◆◆

diff — compare files line by line

Two files, one truth: the exact lines that differ.

Every git diff you have ever read is this command wearing a costume. Learn the original and the unified format stops being a mystery of line numbers and becomes a sentence you can read aloud.

AI-generated draft · reviewed and editedThis text was generated with AI as a first draft, then reviewed and edited by the author, who holds editorial responsibility for it.

2026-09-24 · 5 min read

$ diff

What it does

diff compares two files (or entire directory trees with -r) line by line and prints just the differences. Two files that match produce no output. When they differ, diff shows the offending lines: a line added on one side, removed on the other, or changed — each prefixed with < for the first file and > for the second. Its exit status is a truth machine: 0 means identical, 1 means different, 2 means trouble. That exit code is what makes diff usable inside shell scripts and is the whole reason git, patch, and every CI pipeline lean on it.

Why it matters

diff is the answer to the oldest sysadmin question: 'what changed, and where?' You point it at two nginx configs, two versions of a deploy script, two directories before and after a release, and diff tells you the exact lines. Its sibling patch can then apply those differences to other copies of the original for you. Master diff's exit code and the -r and -q flags and you stop eyeballing files side by side — the machine does the scanning.

Example

$ diff nginx-old.conf nginx-new.conf
4a5
>     server_tokens off;

Normal diff. '4a5' reads 'after line 4 of file 1, add the line that is line 5 of file 2'. < means from the first file, > from the second. Exit code is 1 because the files differ.

$ diff -r /tmp/d1 /tmp/d2
Only in /tmp/d1: extra.txt
Only in /tmp/d2: other.txt
diff -r /tmp/d1/sub/config /tmp/d2/sub/config
2c2
< line2
---
> line2 changed

-r recurses into directories, reporting files present in only one tree and recursing into the ones that exist on both. This is the go-to check before and after a deploy.

$ diff -q nginx-old.conf nginx-new.conf
Files nginx-old.conf and nginx-new.conf differ

-q (brief) prints only a yes/no, making it perfect for shell scripts: if diff -q a.txt b.txt; then echo same; else echo diff; fi — no noise to parse.

$ diff -y nginx-old.conf nginx-new.conf
server {							server {
    listen 80;							    listen 80;
    server_name example.com					    server_name example.com;
    root /var/www/html						    root /var/www/html;
							      >	    server_tokens off;
}								}

-y prints both files side by side with a > marker where they diverge. Great for a quick eyeball on short configs.

Common flags

-u
unified format with context lines — the git-diff style; best for humans and patch
-q / --brief
report only whether files differ, used in scripts to test equality
-s
say when files are IDENTICAL (default is silence on a match)
-r
recursively compare matching files inside two directories
-y
side-by-side output in two columns instead of a change list
-N
treat files missing from one side as empty, so additions show as content not 'only-in'
-x PATTERN
exclude files matching a pattern when recursing (e.g. -x '*.log')

History

Origin

diff was written by Douglas McIlroy at Bell Labs and first shipped in the fifth edition of Unix (1974). McIlroy headed the lab's computing research and had a knack for small tools that composed — diff was the template for the whole 'compare two things' genre, and it spawned patch, sdiff, and the format that still powers version control today.

The unified revolution

The default diff format (the 4a5 / 2c2 you see by default) is terse and hard to read. In 1990 Wayne Davison designed the unified format — the -u you now reach for reflexively — which folds removals and additions into one run of context lines. It was so obviously better that it became the de facto standard, and it is exactly what git diff, GitHub, and every code-review tool print today.

Fun facts

Pros & cons

pros

  • + Universal: present on every Unix-like system since 1974, no install
  • + Exit status 0/1/2 makes it scriptable — it doubles as an equality test
  • + Handles whole directory trees with -r, plus exclusions and side-by-side views

cons

  • − Default format is terse and hard to read; you must remember -u
  • − Line-oriented only — moving a single line within a big file registers as delete + add
  • − No smart move/rename detection like git diff; it compares text, not intent

Takeaways

  1. 1Default to diff -u: context lines make changes readable and patch-friendly
  2. 2Use diff -q in scripts as a quiet equality test — check the exit code, not output
  3. 3Diff whole trees before/after a deploy with diff -r dir1 dir2
  4. 4Reach for diff -s to explicitly confirm two files are identical
  5. 5Read @@ -a,b +c,d @@ as old-file range a–b maps to new-file range c–d

Related commands