Compare and Merge Two Files Safely with sdiff

Two config files, one working and one not, and sdiff is the tool that puts them side by side so you can actually see which line changed. The examples use GNU sdiff from diffutils 3.10, installed here as package version 1:3.10-1ubuntu0.1.

Allow about ten minutes. You need two readable text files and an ordinary shell. The comparison commands do not need elevated privileges. The merge example writes a new output file, so keep the original inputs until you have checked the result.

1. Confirm the installed command

Check which executable will run and record its version. These are read-only commands:

$ command -v sdiff
/usr/bin/sdiff
$ sdiff --version
sdiff (GNU diffutils) 3.10
$ dpkg-query -W -f='${Package} ${Version}\n' diffutils
diffutils 1:3.10-1ubuntu0.1

The command takes exactly two file operands. A dash can stand in for either operand to read that side from standard input, but a here-document or a pipe makes a comparison harder to audit later. Start with named files when you are diagnosing a real difference.

Checkpoint: both paths should be readable before you compare them:

$ test -r ./old.conf && test -r ./new.conf && echo 'both inputs are readable'
both inputs are readable

2. Read the side-by-side output

Run the basic comparison. The left input is printed on the left, the right input on the right. A vertical bar marks a changed line, a less-than marker marks a line present only on the left, and a greater-than marker marks a line present only on the right:

$ sdiff old.conf new.conf
listen = 8080                         listen = 8080
mode = test                         | mode = production
cache = on                             cache = on
                                      > timeout = 30
$ printf 'exit status: %s\n' "$?"
exit status: 1

Do not treat status 1 as a command failure. GNU sdiff returns 0 when the inputs are the same, 1 when they differ, and 2 when it hits trouble such as a missing file. Capture the status immediately if a script needs to tell those cases apart:

$ sdiff old.conf new.conf > comparison.txt
$ status=$?
$ case "$status" in 0) echo identical;; 1) echo different;; *) echo "sdiff error: $status" >&2;; esac
different

3. Make a noisy comparison easier to scan

Whitespace often hides the change you actually care about. Choose an ignore option deliberately, each one can also hide a meaningful formatting change:

For example, this treats indentation changes as uninteresting while keeping other differences visible:

$ sdiff --ignore-space-change old.conf new.conf
listen = 8080                         listen = 8080
mode = test                         | mode = production

If the terminal is narrow, restrict the output width. GNU sdiff defaults to 130 print columns, and -w NUM sets a different limit:

$ sdiff --width=80 old.conf new.conf

Use -s when you only want differences. It suppresses common lines, handy for a quick review but it removes the surrounding context. Use -l for only the left column of common lines, or -t to expand tabs in the output. None of these output choices alter either input file.

4. Create a merged file interactively

Only add -o once you have already inspected the comparison. It starts an interactive merge and sends the selected result to the named output file:

$ sdiff --output=merged.conf old.conf new.conf

Common lines are copied automatically. At each differing section, sdiff shows a prompt. Enter one of these single-letter choices, then press Enter:

The exact prompt includes the changed lines, so decide from the displayed content rather than relying on line numbers. If you choose e, save and exit the editor before sdiff continues. Set an editor explicitly for a predictable result:

$ EDITOR=/usr/bin/nano sdiff --output=merged.conf old.conf new.conf

Warning: do not point --output at either input file. The merge output is a separate file, and overwriting an input can destroy the version you still need for comparison. If you accidentally start writing to the wrong path, use q while the prompt is still active and inspect the file before doing anything else. There is no reliable undo for an overwritten input unless you have a backup, copy or version-control history.

5. Verify the merged result

Inspect the output and compare it against both sources. First, check that it exists and is non-empty when that is expected:

$ test -s merged.conf && echo 'merged file is non-empty'
merged file is non-empty
$ sed -n '1,20p' merged.conf

Then use sdiff again. A status of 0 means your merged file is identical to the left input, which may be correct for some sections but is not general proof the merge went right. Comparing the merged file with each source shows what actually changed:

$ sdiff merged.conf new.conf
$ printf 'against new.conf: %s\n' "$?"
against new.conf: 0
$ sdiff merged.conf old.conf
mode = production                   | mode = test
timeout = 30                         >
$ printf 'against old.conf: %s\n' "$?"
against old.conf: 1

For a final review, read the complete merged file in the application that actually consumes it. sdiff compares text; it does not validate configuration syntax, permissions, service behaviour or security policy. If the file will be loaded by a service, validate it with that service's documented checker before installing it. Do not use sudo for the comparison. If a protected destination is unavoidable, write and verify the merged file in a user-owned directory first, then copy it during a planned change window with a known rollback copy.

6. Diagnose common failures

Status 2 means sdiff could not complete the comparison at all. Re-run without redirection so the diagnostic stays visible:

$ sdiff old.conf missing.conf
sdiff: missing.conf: No such file or directory
$ printf 'exit status: %s\n' "$?"
exit status: 2

Check spelling, path and read permission. If output is clipped, increase -w or pipe into a pager such as less. If tabs make the columns look misleading, try -t. Do not stack every ignore option at once: stripping out too much whitespace or case information can turn a real change into what looks like a clean comparison.

Done means