Skip to content
Linux Basics: Compare Sorted Lists with GNU comm

Linux Basics: Compare Sorted Lists with GNU comm

October 24, 2026

When you have two inventories, the useful questions are often what they share and what appears in only one. GNU comm answers those questions for sorted text files. Unlike a line-by-line edit diff, it treats the input as ordered lists to compare.

These examples were tested on Linux with GNU Bash 5.2.37 and GNU coreutils 9.7. They use invented service names, not a real deployment. Each script sets LC_ALL=C so sorting and comparison use the same predictable ordering.

Prepare a scratch directory

You need Bash, GNU comm and sort, a text editor, and the mktemp, rm, and rmdir utilities. Keep using the same terminal. Save each named source file here, then run it once in order. No administrator access is needed.

start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1

1. Understand the three output columns

Save this as comm-three-columns.sh:

#!/usr/bin/env bash
set -eu
export LC_ALL=C
printf '%s\n' apple banana fig > left.txt
printf '%s\n' banana cherry fig > right.txt
printf 'Only left|Only right|Both\n'
comm --check-order --output-delimiter='|' left.txt right.txt

Run it:

bash comm-three-columns.sh

Output:

Only left|Only right|Both
apple
||banana
|cherry
||fig

The first column is unique to the first file, the second is unique to the second file, and the third is shared. The two leading separators before banana place it in the shared column. Trailing empty columns are not padded out, so apple has no trailing separators.

GNU comm normally separates columns with tabs. The custom | delimiter makes column positions visible here; it does not turn the result into a general-purpose CSV file. The GNU comm manual explains column suppression and ordering requirements.

2. Produce missing and unexpected inventories

Save this as comm-inventory-difference.sh:

#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
printf '%s\n' web api cache api | sort -u > expected.txt
printf '%s\n' worker web api | sort -u > actual.txt
printf 'Missing:\n'
comm --check-order -23 expected.txt actual.txt
printf 'Unexpected:\n'
comm --check-order -13 expected.txt actual.txt
printf 'Shared:\n'
comm --check-order -12 expected.txt actual.txt

Run it:

bash comm-inventory-difference.sh

Output:

Missing:
cache
Unexpected:
worker
Shared:
api
web

The numbers name columns to hide, not columns to select. -23 hides columns two and three, leaving entries found only in the expected list. -13 leaves entries unique to the actual list; -12 leaves the intersection.

sort -u both orders the fixtures and removes the repeated api. This gives set-like membership semantics: being listed twice does not create a second required service. Do not remove duplicates if multiplicity carries meaning in your data; that calls for a different comparison model.

This report only identifies differences. It does not start, stop, create, or delete anything. Review a real inventory’s meaning before using its differences to drive actions.

3. Reject unsorted input and discard partial results

Save this as comm-check-order.sh:

#!/usr/bin/env bash
set -eu
export LC_ALL=C
printf '%s\n' beta alpha > unsorted.txt
printf '%s\n' alpha beta > ordered.txt
if comm --check-order -12 unsorted.txt ordered.txt \
  > candidate.txt 2> order-error.txt; then
  printf 'Unexpected success\n' >&2
  exit 1
else
  status=$?
  test -s order-error.txt
  rm -- candidate.txt
  printf 'Comparison rejected: status %s\n' "$status"
  printf 'Candidate output discarded\n'
fi

Run it:

bash comm-check-order.sh

Output:

Comparison rejected: status 1
Candidate output discarded

The first fixture deliberately violates the required order. --check-order rejects it, and the conditional handles that expected failure. The error text is retained separately while the candidate result is removed. Do not use partial comparison output after an ordering error.

The script finishes successfully because rejection is the expected outcome of this test. For real input, fix the preparation step rather than using --nocheck-order to hide the problem.

Keep in mind

Both input files must use the same ordering as the comparison. Numeric sorting is not interchangeable with the lexical ordering used here. Preserve one locale consistently through preparation and comparison.

A successful comm normally returns zero even when the lists differ. Its exit status signals whether comparison succeeded, not whether the lists are equal. Inspect the relevant output if differences should affect a later decision.

These examples assume one complete item per line. An embedded newline would split an item. GNU comm -z supports NUL-delimited records for workflows that need them, but the producer and sorting stages must also use the same record separator.

Clean up

Remove only these practice files, then return to your original directory:

rm -- comm-three-columns.sh comm-inventory-difference.sh comm-check-order.sh \
  left.txt right.txt expected.txt actual.txt unsorted.txt ordered.txt order-error.txt
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dir

Acknowledgements

This post was created with assistance from AI.

Last updated on