from monochrome diff to changes readable at a glance
A raw diff output is technically complete but hard to read in a terminal, because lines marked with plus and minus barely stand out visually. This article shows how colored diff output emerges in Bash scripts, from ready-made tools like colordiff and git diff to your own ANSI coloring with awk for edge cases no standard tool covers.
Table of Contents
- 1. Why monochrome diff in scripts is underestimated
- 2. colordiff: the fastest solution without a custom build
- 3. git diff --color for versioned comparisons
- 4. Custom coloring with awk and ANSI codes
- 5. Coloring the side-by-side comparison with diff -y
- 6. Correctly evaluating diff exit codes in scripts
- 7. Terminal detection: color only when it makes sense
- 8. Practical example: config comparison before a deployment
- 9. Tools for colored diffs compared
- 10. Summary
- 11. FAQ
1. Why monochrome diff in scripts is underestimated
The classic diff command delivers technically complete information about what changed between two files, but the plain text output with < and > as markers is hard to scan in a terminal. Colored diff output solves this perception problem by highlighting added lines in green, removed lines in red, and changed regions in yellow. The difference jumps out immediately with longer diffs, while a monochrome output has to be read line by line.
In your own Bash scripts, for example for configuration comparisons before a deployment or for backup verification, colored diff output is often overlooked because diff itself does not support color by default. Yet the effort of adding color is small, both via ready-made tools and via a simple custom implementation. This article shows both paths and clarifies when each approach pays off.
2. colordiff: the fastest solution without a custom build
colordiff is a lightweight Perl wrapper around the classic diff command that analyzes the output line by line and adds ANSI color codes without changing the underlying diff logic. The call is straightforward: colordiff file1 file2 instead of diff file1 file2, and all the usual diff options such as -u for unified diff format keep working unchanged, since colordiff simply passes them through to diff.
The great advantage of colordiff in Bash scripts is that no custom parsing logic is needed. The tool handles all detection of additions, deletions and context lines and colors them consistently. The color schemes can be customized via a configuration file ~/.colordiffrc, which is practical for teams wanting a unified style across multiple scripts, without repeating color logic in every script.
#!/usr/bin/env bash
set -euo pipefail
compare_configs() {
local file_a="$1"
local file_b="$2"
if command -v colordiff &>/dev/null; then
colordiff -u "$file_a" "$file_b"
else
echo "[INFO] colordiff not found, falling back to plain diff" >&2
diff -u "$file_a" "$file_b"
fi
}
compare_configs /etc/nginx/nginx.conf.bak /etc/nginx/nginx.conf
3. git diff --color for versioned comparisons
For files managed in a Git repository, git diff --color is often the more pragmatic choice, since no separate tool needs to be installed as long as Git is already present. With git diff --no-index --color file1 file2, git diff can even be used for files outside a repository, which makes this option interesting for plain file comparisons in Bash scripts, independent of any existing version control.
The advantage of git diff over colordiff lies in additional features such as word diff with --word-diff, which highlights changes within a line instead of only line by line. For configuration files, where often only a single value inside a long line changes, this finer granularity is significantly more informative than a pure line comparison, where the entire line is marked as changed.
#!/usr/bin/env bash
set -euo pipefail
# git diff --no-index works even outside a Git repository
git --no-pager diff --no-index --color=always \
/etc/app/settings.yml.bak /etc/app/settings.yml || true
# Word-level diff highlights the changed value inside a long line
git --no-pager diff --no-index --color=always --word-diff \
/etc/app/settings.yml.bak /etc/app/settings.yml || true
4. Custom coloring with awk and ANSI codes
Neither colordiff nor git diff are guaranteed to be present on every target system, especially on minimal server images. For this case, colored diff output can be built yourself with plain diff and awk. The principle: the output of diff in unified format is piped through awk line by line, which decides based on the first character of each line which ANSI color to apply, green for lines starting with +, red for lines starting with -.
This custom build has a decisive advantage over the ready-made tools: full control over the color scheme and no additional dependency beyond awk, which is preinstalled on practically every Unix system. The downside is a somewhat higher maintenance effort, since edge cases like the header lines of the unified diff format (--- and +++) must be explicitly distinguished from the normal plus and minus logic to avoid being accidentally colored as changed lines.
#!/usr/bin/env bash
set -euo pipefail
colorize_diff() {
awk '
/^\+\+\+/ { print "\033[1m" $0 "\033[0m"; next } # file header (bold)
/^---/ { print "\033[1m" $0 "\033[0m"; next } # file header (bold)
/^\+/ { print "\033[32m" $0 "\033[0m"; next } # added line (green)
/^-/ { print "\033[31m" $0 "\033[0m"; next } # removed line (red)
/^@@/ { print "\033[36m" $0 "\033[0m"; next } # hunk header (cyan)
{ print }
'
}
diff -u old_config.yml new_config.yml | colorize_diff
5. Coloring the side-by-side comparison with diff -y
For short files with few lines, the side-by-side view with diff -y is often clearer than the unified format, because both versions appear next to each other instead of one after another. Without color, though, this view is hard to scan, since the difference between unchanged and changed lines is only recognizable by the narrow separator in the middle. Colored diff output here especially highlights the separator itself, for example | for changed, < for lines only present on the left and > for lines only present on the right.
colordiff supports -y directly and colors the separators automatically, which makes this combination the simplest solution for side-by-side comparisons. Anyone using the custom build from the previous section instead has to reproduce the detection of the middle separator themselves with a regular expression in awk, which takes a bit more effort but works just as well.
#!/usr/bin/env bash
set -euo pipefail
# Side-by-side comparison with automatic color highlighting
if command -v colordiff &>/dev/null; then
colordiff -y -W 120 old_config.yml new_config.yml
else
diff -y -W 120 old_config.yml new_config.yml
fi
6. Correctly evaluating diff exit codes in scripts
An often overlooked detail: diff returns exit code 0 if no differences are found, exit code 1 if differences exist, and exit code 2 on an actual error, for example if one of the two files does not exist. Under set -e, a found difference terminates the script immediately, because exit code 1 is interpreted as an error, even if the difference is the expected and desired result of the check.
For scripts that show colored diff output and then react to the result in a controlled way, the exit code must be caught explicitly, for example with diff_output=$(diff -u a b) || diff_exit=$?. Only with this explicit handling can "no differences", "differences found" and "actual error during comparison" be cleanly distinguished, instead of treating all three cases the same under set -e.
#!/usr/bin/env bash
set -uo pipefail # note: no -e, we handle diff's exit codes explicitly
check_config_drift() {
local baseline="$1"
local current="$2"
diff -u "$baseline" "$current" | colorize_diff
local diff_exit=${PIPESTATUS[0]}
case "$diff_exit" in
0) echo "No drift detected." ;;
1) echo "[WARN] Configuration deviates from baseline." >&2; return 1 ;;
*) echo "[ERROR] Comparison failed, exit code $diff_exit" >&2; return 2 ;;
esac
}
check_config_drift /etc/app/baseline.yml /etc/app/current.yml
7. Terminal detection: color only when it makes sense
Color codes in diff output are only a benefit when the output is actually shown in a terminal that interprets ANSI sequences. If the same output is redirected to a log file or processed further by another script, the escape codes appear as cryptic character sequences interspersed with the actual text, which degrades readability rather than improving it. The check [[ -t 1 ]] determines whether stdout is connected to a real terminal and should precede every color decision.
Both colordiff and git diff --color=auto already handle this detection themselves and automatically disable color when the output is redirected. With the custom awk solution from section 4, on the other hand, this check must be added manually, for example by only calling the colorize_diff function when [[ -t 1 ]] is true, and otherwise passing the unmodified diff output straight through.
8. Practical example: config comparison before a deployment
A realistic use case for colored diff output is checking configuration files before a deployment, where an operator needs to recognize at a glance which values have changed since the last known state. A script that automatically compares the current configuration with a saved reference version before every deployment and displays the result in color significantly reduces the risk of overlooking an unintended change, compared to monochrome output.
Combined with the exit code patterns from section 6, such a script can additionally be used as a gate in the deployment process: if differences are found, the script shows the colored diff output and explicitly asks for confirmation before the deployment continues. This pattern combines pure visibility of changes with an active safeguard against accidental configuration drift.
9. Tools for colored diffs compared
Several paths are available for colored diff output in Bash scripts, differing in dependency, feature scope and control over the color scheme.
| Tool | Dependency | Word diff | Best use case |
|---|---|---|---|
| colordiff | External (package manager) | No | Fast solution without a custom implementation |
| git diff --color | External (usually present) | Yes, with --word-diff | Configuration comparisons with fine granularity |
| diff + awk (custom) | Only awk (standard) | No, without extra effort | Minimal server images without extra packages |
| diff -y (monochrome) | None | No | Only for very short, rare comparisons |
For most maintenance scripts, a combination is the most robust solution: prefer colordiff or git diff --color, with a fallback to the self built awk solution if both tools are missing on the target system. That keeps colored diff output available in every environment, without a script failing due to missing packages.
Mironsoft
Shell automation and CLI tooling for development teams
Configuration drift getting lost in the terminal?
We build colored diff output with robust exit code handling into your deployment and verification scripts, including a fallback for environments without colordiff.
Diff tooling
Integrating colordiff, git diff and custom ANSI coloring into scripts
Deployment gates
Configuration comparison with confirmation before critical deployments
Robust scripts
Correct exit code handling for reliable verification routines
10. Summary
Colored diff output makes changes between files in Bash scripts noticeably faster to grasp than the monochrome default output of diff. colordiff is the fastest solution without a custom implementation, git diff --color with --word-diff additionally offers finer granularity for configuration files, and a custom build with awk and ANSI codes also works where neither of the two tools is available.
Two details matter for production use: correctly evaluating the diff exit codes so that "no differences", "differences found" and "actual error" are cleanly distinguished, and terminal detection with [[ -t 1 ]] so color codes do not end up as cryptic character sequences in log files. Once these patterns are encapsulated in a reusable function, you get colored diff output that works consistently in every maintenance and deployment script.
Colored diff output in Bash — The essentials at a glance
Ready-made tools
colordiff for a fast solution, git diff --color --word-diff for finer granularity.
Custom build
diff | awk with ANSI codes for environments without extra packages, full control over colors.
Exit codes
0 no differences, 1 differences found, 2 actual error. Do not use unchecked under set -e.
Terminal detection
Check [[ -t 1 ]] so color codes do not end up in log files or pipes.