Сверить два инвентаря через comm: новые, исчезнувшие и общие записи

После обновления окружения нужно быстро увидеть, какие пакеты появились и какие исчезли. Обычный diff показывает построчные правки, но при изменении порядка выдаёт шум. Для инвентаря часто важнее принадлежность имени одному из двух наборов. Команда comm сравнивает два отсортированных списка и разделяет записи на три категории.

Сначала решите, является ли вход множеством. Если один пакет по ошибке записан дважды, должен ли дубль влиять на результат? Для сравнения установленных имён обычно нет: нужны уникальные значения. Для сравнения событий или количества установок дедупликация уже потеряет информацию. Ниже рассматриваем именно множество полных строк.

Подготовим нормализованные входы

Пример создаёт два инвентаря и отдельные отсортированные представления. Все записи — технические идентификаторы без заголовков.

printf '%s\n' api worker api > before.txt
printf '%s\n' scheduler worker > after.txt
LC_ALL=C sort -u before.txt > before.sorted
LC_ALL=C sort -u after.txt > after.sorted
LC_ALL=C comm -23 before.sorted after.sorted > removed.txt
LC_ALL=C comm -13 before.sorted after.sorted > added.txt
LC_ALL=C comm -12 before.sorted after.sorted > common.txt
printf 'removed: '; cat removed.txt
printf 'added: '; cat added.txt
printf 'common: '; cat common.txt

Получатся removed: api, added: scheduler, common: worker. В параметре -23 подавляются вторая и третья категории, поэтому остаётся только то, что было в первом файле. -13 оставляет уникальное для второго, -12 — общее. Это легче запомнить, связав цифры с тремя колонками исходного вывода comm.

LC_ALL=C используется и при подготовке, и при сравнении. comm требует одинакового порядка сопоставления строк. Для инвентарей технических имён удобно закрепить этот порядок явно, чтобы перенос между машинами не зависел от пользовательской локали.

Не используйте статус как признак различий

У comm успешный статус не означает, что наборы одинаковы. Он означает, что сравнение выполнено. Для проверки «нет новых пакетов» смотрят на размер added.txt после успешной команды. Если нужно остановить выпуск при добавлениях, условие должно проверять непустой файл, а не код 1 как у diff.

Ошибки чтения и нарушения сортировки должны останавливать дальнейшее использование результата. GNU comm предлагает --check-order для более явного контроля входов. Но правильная проверка статуса остаётся обязательной: частичный stdout, появившийся до ошибки, не является готовым отчётом.

Не сравнивайте только название пакета, если задача выпуска требует контроля версии. В строку можно включить имя и версию в стабильном формате, тогда обновление версии даст удаление старой пары и добавление новой. Если нужен отчёт именно «обновилось с A на B», потребуется соединение по имени и разбор версий. Это другой результат, который comm сам не строит.

Очистка данных должна быть симметричной

CRLF, пробел в конце и разный регистр создают разные полные строки. Если источник допускает такую вариативность, примените одинаковую нормализацию к обоим входам. Не обрезайте произвольные пробелы вслепую: для некоторых идентификаторов они являются частью значения. Лучше зафиксировать формат экспорта и проверять его перед сравнением.

Не включайте заголовок таблицы в набор пакетов. Если экспорт содержит служебные строки с датой, они будут каждый раз появляться в added и removed, заслоняя полезные изменения. Сначала выделите колонку идентификатора подходящим парсером и только затем сортируйте.

В программе Linux и Bash для DevOps-инженеров повторяемые операции превращаются в проверяемые скрипты. Откройте программу и продолжите к инвентаризации, где формат входа, смысл разницы и условие остановки выпуска определены до автоматического действия.

Ещё по теме

Продолжить на практике

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.