diff compares two files line by line and shows what changed. On servers it answers questions like “what did I change in this config?”, “how does this server’s nginx.conf differ from that one?” and “what did the package update change?”.
Unified format: the one to use
diff -u nginx.conf.bak nginx.conf
--- nginx.conf.bak 2026-10-12 09:10:22
+++ nginx.conf 2026-10-14 15:31:07
@@ -12,7 +12,8 @@
sendfile on;
tcp_nopush on;
- keepalive_timeout 65;
+ keepalive_timeout 30;
+ client_max_body_size 64m;
types_hash_max_size 2048;
How to read it:
---is the old file and+++is the new one.@@ -12,7 +12,8 @@— this “hunk” starts at line 12 and covers 7 lines in the old file and 8 in the new.- Lines starting with
-were removed, lines with+were added, and lines with a space are unchanged context.
This is the same format git diff uses. The default “normal” diff output (12c12, <, >) is harder to read, so get used to -u.
Exit status
diff exits with 0 if the files are identical, 1 if they differ and 2 on errors. Use that in scripts:
if diff -q current.conf expected.conf > /dev/null; then
echo "unchanged"
fi
-q only reports whether the files differ.
Readable output
diff -u --color=auto a b # coloured
diff -y a b # side by side
diff -y --suppress-common-lines a b
diff -y -W 200 a b # wider columns
For a nicer experience, vimdiff a b shows files side by side with highlighting. git diff --no-index a b gives git’s colouring and word-level diffs (--word-diff) for files that aren’t in a repository.
Ignore noise
diff -u -w a b # ignore all whitespace
diff -u -b a b # ignore changes in the amount of whitespace
diff -u -B a b # ignore blank lines
diff -u -i a b # ignore case
diff -u --strip-trailing-cr a b # ignore Windows vs Unix line endings
diff -u -I '^#' a b # ignore changed lines that match a regex (comments here)
Compare directories
diff -rq /etc/nginx /backup/etc/nginx # which files differ or exist only on one side
diff -ru old-site/ new-site/ # full recursive diff
diff -ru -x '*.log' -x 'cache' a/ b/ # exclude patterns
For large trees, rsync -rcn --delete --out-format='%n' a/ b/ is another way to list differences without transferring anything. See rsync.
Compare with command output or a remote file
Process substitution treats command output as a file:
diff -u <(ssh web1 cat /etc/nginx/nginx.conf) <(ssh web2 cat /etc/nginx/nginx.conf)
diff <(sort list1.txt) <(sort list2.txt)
diff -u <(dpkg --get-selections) <(ssh other dpkg --get-selections) # installed packages
From stdin, use - as one of the filenames:
curl -s https://example.com/robots.txt | diff -u - local-robots.txt
After package upgrades
When apt asks what to do about a modified config file, choose “show the differences”. Later, the distribution’s version is saved as *.dpkg-dist or *.dpkg-new, so you can compare:
diff -u /etc/ssh/sshd_config /etc/ssh/sshd_config.dpkg-dist
On RHEL-family systems, look for .rpmnew files.
Create and apply patches
diff -u original.conf fixed.conf > fix.patch
patch original.conf < fix.patch # apply
patch -R original.conf < fix.patch # revert
patch --dry-run -p1 < changes.patch # test first
For directories, run diff -ruN old/ new/ > changes.patch and apply it from inside the old directory with patch -p1 < changes.patch. -N treats missing files as empty, so new files are included.
Related tools
| Tool | Use |
|---|---|
cmp |
Compare binary files byte by byte |
comm |
Lines common to two sorted files |
sha256sum |
Check whether files are identical across servers |
colordiff |
Coloured diff output |
git diff |
Track config changes over time (etckeeper puts /etc in git) |
etckeeper is worth installing on servers. It commits /etc to git automatically on every package change, so git log -p shows exactly what changed and when.
Quick reference
| Task | Command |
|---|---|
| Unified diff | diff -u a b |
| Just “differ?” | diff -q a b |
| Side by side | diff -y a b |
| Ignore whitespace | diff -uw a b |
| Directories | diff -ru dir1 dir2 |
| Remote vs local | diff -u <(ssh h cat f) f |
| Make patch | diff -u a b > p.patch |
| Apply patch | patch a < p.patch |
Related: sort and uniq and Git cheat sheet.