Як порівняти два текстові файли в терміналі Linux

Потрібно знайти розбіжності між двома текстовими документами? Команда `diff` стане вашим надійним помічником. Цей посібник демонструє, як просто та ефективно використовувати `diff` в операційних системах Linux та macOS.

Знайомство з командою diff

Команда `diff` призначена для порівняння двох файлів і виведення списку їхніх відмінностей. Точніше, вона показує перелік змін, які потрібно внести у перший файл, щоб він став ідентичним другому. Якщо ви розумітимете це, вам буде легше інтерпретувати вихідні дані `diff`. Ця команда спочатку розроблялася для виявлення відмінностей між файлами з вихідним кодом, і результати її роботи можна використовувати в інших програмах, таких як `patch`. У цьому посібнику ми розглянемо найбільш практичні та зрозумілі для користувача способи застосування `diff`.

Розглянемо приклад порівняння двох файлів. Порядок файлів, вказаних у командному рядку, визначає, який файл `diff` вважатиме “першим”, а який “другим”. У прикладі нижче `alpha1` є першим файлом, а `alpha2` – другим. Обидва файли містять фонетичний алфавіт, але `alpha2` був відредагований, щоб відрізнятися від `alpha1`.

Щоб порівняти файли, введіть `diff`, потім пробіл, назву першого файлу, пробіл і назву другого файлу, після чого натисніть клавішу Enter.

diff alpha1 alpha2

Як інтерпретувати ці результати? Насправді, це не так складно, як здається. Кожна відмінність відображається у вигляді рядка, позначеного спеціальною міткою. Мітка має формат `число1літерачисло2`, наприклад `4c4`. Перше число – це номер рядка у файлі `alpha1`, а друге – номер рядка у файлі `alpha2`. Літера між ними може означати:

  • `c`: рядок у першому файлі потрібно **змінити**, щоб він став ідентичним рядку у другому файлі.
  • `d`: рядок у першому файлі потрібно **видалити**, щоб він відповідав другому файлу.
  • `a`: у перший файл потрібно **додати** додатковий вміст, щоб він став ідентичним другому.

У нашому прикладі `4c4` вказує, що четвертий рядок файлу `alpha1` потрібно змінити, щоб він відповідав четвертому рядку файлу `alpha2`. Це перша знайдена `diff` відмінність.

Рядки, що починаються з `<`, відносяться до першого файлу (`alpha1`). Рядки, що починаються з `>`, відносяться до другого файлу (`alpha2`). Рядок `< Delta` повідомляє нам, що четвертий рядок `alpha1` містить слово “Delta”. Рядок `> Dave` повідомляє, що четвертий рядок `alpha2` містить слово “Dave”. Отже, щоб ці рядки стали ідентичними, нам потрібно замінити слово “Delta” на “Dave” в четвертому рядку файлу `alpha1`.

Наступна зміна позначена як `12c12`. Згідно з тією ж логікою, це означає, що 12-й рядок `alpha1` містить “Lima”, а 12-й рядок `alpha2` – “Linux”.

Третя зміна вказує на рядок, який був видалений з `alpha2`. Мітка `21d20` означає, що рядок 21 потрібно видалити з першого файлу, щоб обидва файли збігалися з рядка 20.

Четверта відмінність позначена як `26a26,28`. Ця зміна стосується трьох додаткових рядків, доданих до `alpha2`. Зверніть увагу на `26,28` у мітці. Два числа, розділені комою, представляють діапазон номерів рядків. У цьому випадку діапазон – від рядка 26 до рядка 28. Мітка інтерпретується як “в рядку 26 першого файлу потрібно додати рядки з 26 по 28 з другого файлу”. Нам показано три рядки з `alpha2`, які потрібно додати до `alpha1`. Вони містять слова “Чудний”, “Дивний” та “Чарівність”.

Швидкі однорядкові вирази

Якщо вам потрібно лише знати, чи ідентичні два файли, скористайтеся параметром `-s` (повідомити про ідентичні файли).

diff -s alpha1 alpha3

Щоб отримати лаконічну інформацію про те, що два файли відрізняються, використовуйте параметр `-q` (короткий).

diff -q alpha1 alpha2

Важливо відзначити, що якщо файли ідентичні, параметр `-q` не виведе жодної інформації.

Альтернативний формат виводу

Параметр `-y` (пліч-о-пліч) використовує інший формат для відображення відмінностей між файлами. Часто зручно використовувати параметр `-W` (ширина) разом із виводом пліч-о-пліч, щоб обмежити кількість стовпців. Це допомагає уникнути надто широких рядків, які ускладнюють читання результатів. У прикладі нижче ми просимо `diff` створити вивід пліч-о-пліч та обмежити ширину 70 стовпцями.

diff -y -W 70 alpha1 alpha2

Перший файл (`alpha1`) відображається зліва, а другий (`alpha2`) – справа. Змінені, видалені або додані рядки в `alpha2` позначені відповідними символами.

  • `|`: рядок, який був **змінений** у другому файлі.
  • `<`: рядок, який був **видалений** з другого файлу.
  • `>`: рядок, **доданий** до другого файлу, якого немає в першому.

Якщо ви віддаєте перевагу більш компактному виводу пліч-о-пліч, використовуйте параметр `–suppress-common-lines`. Він змусить `diff` відображати лише змінені, додані або видалені рядки.

diff -y -W 70 --suppress-common-lines alpha1 alpha2

Кольорове виділення

Утиліта `colordiff` додає кольорове підсвічування до вихідних даних `diff`, що значно полегшує ідентифікацію відмінностей.

Використовуйте `apt-get` для встановлення `colordiff` у вашій системі, якщо ви використовуєте Ubuntu або інший дистрибутив на базі Debian. В інших дистрибутивах Linux скористайтеся їхнім менеджером пакетів.

sudo apt-get install colordiff

Використовуйте `colordiff` так само, як і `diff`.

Насправді, `colordiff` є обгорткою для `diff`, і `diff` виконує всю основну роботу. Тому всі параметри `diff` працюватимуть з `colordiff`.

Контекстне відображення

Щоб збалансувати між відображенням усіх рядків файлу та показом лише змінених рядків, можна попросити `diff` надати контекст. Це можна зробити двома способами, обидва з яких показують кілька рядків до та після кожного зміненого рядка, щоб ви могли бачити, що відбувається у файлі в місці відмінності.

Перший спосіб використовує параметр `-c` (скопійований контекст).

colordiff -c alpha1 alpha2

Вивід `diff` має заголовок з іменами файлів та часом їхньої зміни. Зірочки `***` позначають перший файл, а тире `—` – другий. Ці символи використовуватимуться для ідентифікації рядків з відповідного файлу.

Рядок зі зірочками посередині `*** 1,7 ***` вказує, що ми розглядаємо рядки з `alpha1`, а саме з першого по сьомий. Змінене слово “Delta” позначено червоним знаком оклику `!`. Перед та після цього рядка показано три рядки незмінного тексту, що дозволяє побачити контекст зміни.

Рядок із тире посередині `— 1,7 —` вказує, що зараз ми розглядаємо рядки з `alpha2`, також з першого по сьомий, і слово “Dave” у четвертому рядку позначено як відмінне.

Кількість рядків контексту (три рядки зверху та знизу) є значенням за замовчуванням. Ви можете вказати іншу кількість рядків контексту, використовуючи параметр `-C` (скопійований контекст) з великої літери “C” та вказавши потрібне число рядків:

colordiff -C 2 alpha1 alpha2

Іншим варіантом є використання параметра `-u` (уніфікований контекст).

colordiff -u alpha1 alpha2

У заголовку, як і раніше, відображаються імена файлів та час їхньої зміни. Тире `-` позначає `alpha1`, а плюси `+` – `alpha2`. Рядки, що починаються зі знака `@`, позначають початок кожної різниці та вказують, які рядки виводяться з кожного файлу.

Знову ж таки, нам показано по три рядки до та після рядка, позначеного як відмінний, щоб ми могли бачити контекст. В уніфікованому форматі рядки з відмінностями показані один над одним. Рядки з `alpha1` мають перед собою тире, а рядки з `alpha2` – плюс. Таким чином, уніфікований контекст в восьми рядках показує ту ж інформацію, що скопійований контекст у п’ятнадцяти.

colordiff -U 2 alpha1 alpha2

Як і слід було очікувати, можна вказати, скільки саме рядків уніфікованого контексту потрібно відображати. Для цього скористайтеся параметром `-U` (уніфікований контекст) з великою літерою “U” і вкажіть потрібну кількість рядків:

Ігнорування пробілів та регістру

colordiff -y -W 70 test4 test5

Розглянемо два додаткових файли: `test4` і `test5`. Вони містять шість імен супергероїв.

Результати показують, що `diff` не виявляє відмінностей у рядках з Чорною Вдовою, Людиною-павуком та Тором. Відмінності є у рядках з Капітаном Америкою, Залізною людиною та Халком.

У чому ж відмінність? У файлі `test5` Халк пишеться з малої літери “h”, а Капітан Америка має додатковий пробіл між “Капітан” та “Америка”. Але що не так з рядком Залізної людини? Видимих відмінностей немає. Тут діє просте правило: якщо ви не бачите різниці, то відповідь – пробіл. Скоріш за все, в кінці цього рядка є один або два пробіли або символ табуляції.

Якщо ці відмінності не мають значення, можна попросити `diff` ігнорувати їх:

  • `-i`: ігнорувати відмінності у регістрі.
  • `-Z`: ігнорувати кінцеві пробіли.
  • `-b`: ігнорувати зміни в кількості пробілів.
  • `-w`: ігнорувати всі зміни пробілів.
colordiff -i -y -W 70 test4 test5

Попросимо `diff` ще раз перевірити ці файли, але цього разу ігноруючи відмінності в регістрі.

colordiff -i -Z -y -W 70 test4 test5

Рядки з “Халк” та “Халк” тепер вважаються ідентичними, і відмінність у регістрі “h” не позначається. Попросимо `diff` ігнорувати також кінцеві пробіли.

colordiff -i -w -y -W 70 test4 test5

Як і очікувалося, відмінність в рядку Залізної людини полягала в кінцевому пробілі, оскільки `diff` більше не позначає цей рядок як відмінний. Залишається Капітан Америка. Попросимо `diff` ігнорувати регістр та всі проблеми з пробілами.

Вказуючи `diff` ігнорувати відмінності, які не є важливими, `diff` повідомляє нам, що для наших цілей файли збігаються. Команда `diff` має набагато більше параметрів, але більшість з них стосуються створення машиночитаних результатів. Детальніше про них можна дізнатися на сторінці manual в Linux.

Параметри, які ми розглянули, допоможуть вам відстежувати відмінності між версіями ваших текстових файлів, використовуючи командний рядок.