Сравнение файлов в Linux – утилита diff
Очень часто возникают ситуации, когда необходимо сравнить содержимое двух или нескольких текстовых файлов. Например, для системных администраторов важно знать о конкретных различиях в конфигурации обслуживаемых систем. Программистам и разработчикам не менее важно быстро выявить различия в коде проектов, а также быстро создать патч, отражающий соответствующие изменения между двумя файлами или разными версиями одного. Это лишь самый распространённый перечень ситуаций, когда использование специализированных утилит для сравнения содержимого файлов приходится очень кстати и экономит кучу времени. Одной из таких утилит в системах Linux является diff – о ней и пойдёт речь в данной статье.
Основные возможности утилиты diff
Главное и, наверное, самое ценное преимущество diff в том, что эта утилита прекрасно работает через интерфейс командной строки. Вот почему она довольно популярна среди системных администраторов. Однако, это обстоятельство вполне закономерно объясняет и имеющийся у diff недостаток — работа с ней недостаточно наглядна, а для новичков довольно сложна.
В отличие от других аналогичных утилит, которые можно использовать исключительно в графической среде, diff прекрасно справляется со своими задачами в командной оболочке. Ну а некоторые неудобства, связанные с восприятием выводимых результатов работы утилиты — это в большинстве случаев, всего лишь недостаток пользовательского опыта работы как в командной оболочке, так и с самой утилитой diff. Стоит ещё раз отметить, что порог вхождения у неё для новичков действительно, довольно высок.
Утилита diff принимает на вход имена файлов, которые необходимо построчно сравнить, а также набор опций, управляющих режимами работы самой утилиты. В официальном руководстве (доступном по команде man diff) можно получить информацию о всех доступных для diff опциях. В данной же статье описываются лишь основные и часто используемые опции, а также простые и наглядные приёмы использования программы.
Синтаксис команды diff и её основные опции
Правила использования утилиты diff задаются командой, имеющей следующий синтаксис:
Здесь в качестве [FILES] задаются через пробел имена файлов для сравнения. [OPTION] определяет опции работы команды, основные из которых приведены в следующей таблице:
Перед тем, как использовать утилиту diff на практике, нужно разобраться с форматом вывода результатов сравнения. Вывод команды diff представляет собой последовательность инструкций, которые необходимо выполнить, чтобы файлы стали идентичными. Эти инструкции строятся на следующих обозначениях:
Вывод, например, может быть таким:
Здесь запись «2c2» означает, что вторая строка в файле №1 (оригинал) отличается от соответствующей (второй) строки в файле №2. Символ « » — файлу №2. Запись «—» чисто косметическая и предназначена для визуальной удобочитаемости результатов. Для наглядности, данный вывод соответствует результату сравнения двух файлов (file1 и file2) со следующим содержимым:
Использование команды diff
Теперь, для более наглядной демонстрации работы утилиты diff можно несколько усложнить условия задачи из предыдущей главы, изменив файл №2 следующим образом:
Тогда, выполнив команду
будет получен следующий вывод:
Здесь выражение «2c2,3» говорит о том, что второй строке (line2) в файле file1 соответствуют изменения в file2 в виде строк «line11» и «line22». Запись «2,3» означает диапазон строк в file2, содержащих изменения относительно строки №2 в file1. Запись «3c5,6» говорит о том, что после строки №3 оригинального файла в его изменённой версии (file2) были добавлены строки № 5 и №6, т. е. «line4» и «line5».
Создание патчей (заплаток) с помощью утилиты diff
Одной из особенностей diff является использование опции «-u» для создания патчей. Которые могут быть использованы для приведения содержимого файла к актуальному состоянию. Это очень удобно, ведь все инструкции для актуализации содержатся в одном файле-патче, который может быть обработан автоматически с помощью специализированной утилиты, например patch. Вывод для примера из предыдущей главы с использованием опции «-u» будет следующим:
Заключение
В заключение следует отметить, что использование утилиты diff вручную в командной оболочке довольно трудоёмко, неудобно и ненаглядно. Но в данном случае важно, что задачи по сравнению файлов могут быть в принципе выполнены. В настоящее время утилита diff используется для построения вокруг неё программных обёрток с графическим пользовательским интерфейсом (подобно kompare, diffmerge и т. д.), что и позволяет использовать её с максимальной эффективностью.
Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.
Команда diff в linux
Команда diff предназначена для задействования одноименной утилиты, осуществляющей сравнение двух указанных пользователем файлов и вывод информации об их различиях. Эта утилита может работать как с текстовыми, так и с бинарными файлами, но в подавляющем большинстве случаев используется для поиска различий в обычных текстовых файлах или файлах исходного кода. Благодаря существованию утилиты patch она может использоваться для внесения изменений в исходный код открытых программных проектов.
Базовый синтаксис команды выглядит следующим образом:
$ diff [параметры] файл1 файл2
Примеры использования
Сравнение двух текстовых файлов
Для начала рассмотрим содержимое двух текстовых файлов, которые будут сравниваться.
Это содержимое файла sample1.txt:
It is a truth universally acknowledged, that a single man in possession
of a good fortune, must be in want of a wife.
However little known the feelings or views of such a man may be on his
first entering a neighbourhood, this truth is so well fixed in the minds
of the surrounding families, that he is considered the rightful property
of some one or other of their daughters.
А это — содержимое файла sample2.txt:
However little known the feelings or views of such a man may be on his
first entering a neighbourhood, this truth is so well fixed in the minds
of the surrounding families, that he is considered the rightful property
of some one or other of their daughters.
«My dear Mr. Bennet,» said his lady to him one day, «have you heard that
Netherfield Park is let at last?»
Mr. Bennet replied that he had not.
Для сравнения этих двух файлов достаточно выполнить команду:
$ diff sample1.txt sample2.txt
В результате будет получен следующий вывод, представляющий собой описание различий содержимого этих файлов:
1,3d0
7a5,9
>
> «My dear Mr. Bennet,» said his lady to him one day, «have you heard that
> Netherfield Park is let at last?»
>
> Mr. Bennet replied that he had not.
В результате будет получен следующий вывод:
Сравнение файлов исходного кода
В случае файлов исходного кода используется унифицированный формат вывода и дополнительные параметры утилиты, кроме того, чаще всего вывод сохраняется в файлах с расширением .patch для последующей отправки разработчикам того или иного программного проекта. Рассмотрим содержимое двух текстовых файлов, которые будут сравниваться.
Это содержимое файла sample1.с:
HuMan: diff
Команда diff служит для выявления различий между двумя файлами или всеми соответствующими файлами в двух директориях. Понятно, что применять команду имеет смысл только в случаях, когда исследуемые файлы или директории весьма схожи по содержанию.
Маны команды diff ограничивапются перечислением опций команды, поэтому для ее освоения пришлось провести увлекательное расследование.
Команда diff без опций
И запустим команду:
Попробуем разобраться с выводом команды. Выражение » > крыса» явно означает, что в правом (т.е. втором) файле есть лишнее слово: «крыса». Сложнее расшифровать выражение 1a2. Поскольку «крыса» вторая строка второго файла, то логично предположить, что цифра 2 означает номер строки, различной в сравниваемых файлах. Проверим предположение, поместив «крысу» на 4 строку:
Так и есть, отличается 4 строка второго файла. Появились и мысли насчет первой цифры, а также буквы «a».
1. Если считать эталонным первый файл, то 3 означает строку первого файла, после которой добавлена строка «крыса», являющаяся 4 строкой второго файла. Буква «a», по-видимому, означает первую букву в английском слове «added» (добавлено).
2. Если считать эталонным второй файл, то команда diff подсказывает, что надо сделать, дабы превратить первый файл во второй. Надо после третьей строки первого файла добавить (add) четвертую строку второго файла. Тогда файлы станут одинаковыми по содержанию.
Осталось рассмотреть случай, когда в сравниваемых файлах одинаковое число строк. Давайте слегка изменим файл cot2.txt, заменив слово «собака» на выражение «собака серая», а «крысу» уберем совсем. Теперь в обоих файлах по три строки.
Программа указывает на разницу во вторых строках файлов. А букву «с» осмелюсь интерпретировать как первую букву слова «change» (заменить). То есть команда подсказывает, что если заменить вторую строку первого файла (cot.txt) на вторую строку второго файла (cot2.txt), то файлы станут одинаковыми.
Поменяем файлы местами:
Как видите, ничего не изменилось, только теперь следует заменить вторую строку файла cot2.txt на вторую строку файла cot.txt.
Появляются некоторые общие соображения:
1. Команда diff не считает какой-либо из файлов эталонным.
2. Команда diff дает подсказку, как сделать файлы одинаковыми.
3. Если вы хотите унифицировать файлы в сторону увеличения, то первым ставьте мЕньший файл.
4. Если вы хотите унифицировать файлы в сторону уменьшения, то первым ставьте бОльший файл.
5.Величина файла измеряется в количестве строк, а не в количестве байт. Если количество строк совпадает, то критерием служит количество слов; если оно совпадает, в дело идут символы.
(Узнать параметры файла можно при помощи команды wc).
Как видите, этот формат тоже требует разъяснения. Очевидно, что в заголовке указаны сравниваемые файлы, показано, какими условными знаками (звездочками или черточками) будут помечаться относящиеся к ним строки вывода; затем указано время модификации файла (похоже, что с точностью до наносекунды!). А вот что такое +0300, не берусь сказать, может быть выяснится по ходу дальнейших исследований.
Далее следует, так сказать, «тело» вывода. Среди соответствующих условных обозначений (звездочек и черточек) указаны интервалы приведенных строк через запятую (***2,8***), а знаком восклицания помечена строка, не совпадающая в сравниваемых файлах.
Добавим строку «крыса» в конец файла cot2.txt:
Из вывода можно понять, что во втором файле добавилась строка «крыса», но не хотел бы я разбираться с различиями многостраничных файлов, где строки состоят не из одного слова, а из настоящих предложений!
Давайте уберем первую строку первого файла «кот», и, заодно, уменьшим число строк контекста до 0:
Здорово! Получилось, что мы не убрали кота из первого файла, а добавили во второй! Явно здесь первый файл служит эталоном. Чтобы убедиться в этом, восстановим кота в первом файле и уберем во втором:
Ну и ну! Нет, эталоном здесь и пахнет. Чтобы понять этот вывод, нужно сильно напрячься. В первом файле, где «кот» есть, почему-то значится «- кот». Вероятно, нужно убрать кота, чтобы строки стали одинаковы. Но почему же тогда на восьмой строке второго файла, где живет «крыса», значится «+ крыса»? В конце концов, я нашел такое объяснение:
Да-а, к этому формату нужно привыкнуть. Впрочем, есть еще унифицированный формат.
Унифицированный формат по умолчанию не выводит строк контекста:
Присмотревшись и вдумавшись, можно понять следующее:
2. Формат даты такой же, как у контекстного формата.
3. Диапазоны строк указаны для обоих файлов и отмечены знаками двойной «собаки».
4. Слова, общие для двух файлов ничем не отмечены (или, если хотите, отмечены пробелом).
5. Знаком минус помечены строки, которые есть только в первом файле, как бы изъятые из первого файла, если считать его эталонным.
6. Знаком плюс помечены строки, которых нет в первом файле, как бы добавленные к нему.
Не знаю как вам, но мне этот формат кажется наиболее понятным.
Между двумя колонками текста находится узкая колонка условных обозначений. Эти обозначения могут быть следующими:
‘|’ Соответствующие строки разные, и либо обе приведены полностью, либо обе не полностью.
‘\’ Соответствующие строки разные, первая строка приведена не полностью.
‘/ ‘ Соответствующие строки разные, вторая строка приведена не полностью.
‘ ‘ Строка содержится только во втором файле.
‘(‘ Строка содержится только в первом файле, но различие игнорируется.
‘)’ Строка содержится только вo втором файле, но различие игнорируется.
—left-column (левая колонка)
По-моему, все кристально ясно, может быть, я начинаю привыкать к этой команде?
—suppress-common-lines
Мы теперь достаточно знаем о синтаксисе команды diff, чтобы и без редактора понять, что означает этот вывод.
1. Инструкции показывают, как превратить первый файл во второй.
2. «8a крыса » означает добавить после восьмой строки строку «крыса «.
3. «5c бизон» означает заменить пятую строку строкой «бизон».
4. 1d значит удалить первую строку.
Однако, при желании, мы можем воспользоваться редактором ed для превращения файла cot.txt в файл cot2.txt.
Затем запустим следующую конструкцию:
и проверим результат:
Полагаю, что «заклинание» в командной строке требует некоторого пояснения:
Мы видим уже знакомый нам скрипт и приписанную командой echo в последней строке букву «w», которая служит командой редактора ed.
Важен факт, что файл cot.txt превратился (по своему содержанию, а не по названию) в файл cot2.txt.
Как уже понятно читателю, команда diff создана программистами и для программистов, отсюда и изобилие различных форматов вывода. Ведь при написании программ чрезвычайно важно сличить разные варианты одной и той же программы, чтобы найти ошибки и разночтения.
Сравнение каталогов
Создадим два каталога: dir1 и dir2.
Сравним две директории:
Без опций команда diff не упоминает о файлах с одинаковым содержимым (a-file и c-file), указывает различия в файле b-file, и сообщает о наличие лишнего файла в директории dir2.
Очень подробно и понятно.
Файл a-file был проигнорирован.
Необходимо заметить, что, при применении метасимволов, ОБРАЗЕЦ следует брать в одинарные кавычки.
Были проигнорированы все файлы, имена которых начинаются с букв «a» и «c».
Форматирование вывода команды diff
Регулировка производительности команды diff
Данная опция запрещает команде diff отбрасывать ЧИСЛО_СТРОК, в начале и в конце файлов, что дает команде больше возможностей для поиска минимального результата. Понятно, что это замедляет работу команды.
Сравнение трех файлов: Команда diff3
Каждое различие отмечено знаком ====. Если различие касается всех трех файлов, то знак не меняется, если различие относится только к двум файлам, то к знаку добавляются цифры 1, 2 или 3, показывающие какой из трех файлов имеет данное отличие. Буквенные обозначения такие же, как в команде diff.
Команда diff3 имеет свои особенности, свойства и опции, которые в этой статье рассмотрены не будут. Интересующихся отсылаю к подробному руководству на русском языке.
Можно представить себе также команды diff4, diff5 и так далее, но практически такая необходимость возникает редко, да и формат вывода станет весьма громоздким.
Интерактивное объединение файлов при помощи команды sdiff
Правка файлов при помощи команды patch
Сначала нужно сравнить два файла при помощи diff и записать результаты в файл patch.file:
Затем применить команду patch:
Пользуясь инструкциями из файла patch.file команда patch перепишет текст файла cot.txt таким образом, что он станет идентичным тексту файла cot2.txt.
Тогда программа patch создаст резервную копию файла cot.txt, а сам файл перепишет.
Команда patch «понимает» различные форматы вывода команды diff и автоматически определяет их. Эта команда также имеет немало опций и форматов, которые здесь рассмотрены не будут. Их описание можно найти в упомянутом уже несколько раз руководстве (на русском языке).
Все опции команды diff
—ignore-file-name-case Игнорирует разницу между строчными и заглавными буквами при сравнении файлов.
—no-ignore-file-name-case Учитывает разницу между строчными и заглавными буквами при сравнении файлов.
—label LABEL Использует LABEL вместо имени файла
—normal Выводит нормальный формат.
—left-column Подавляет вывод правой колонки.
—suppress-common-lines Подавляет вывод одинаковых строк
—tabsize=число_символов Табуляция пропускает число_символов (по умолчанию 8)
—unidirectional-new-file При сравнении каталогов, если файл находится только в одном каталоге из двух, считает что он находится и в первом, но является пустым.
—from-file=FILE1 Сравнивает FILE1 со всеми операндами. FILE1 может быть директорией.
—to-file=FILE2 Сравнивает все операнды с FILE2. FILE2 может быть директорией.
—horizon-lines=ЧИСЛО_СТРОК Не дает отбрасывать последние ЧИСЛО_СТРОК строк начала и первые ЧИСЛО_СТРОК конца файла.
—speed-large-files Использует эвристику для быстрой обработки больших файлов, имеющих много рассеянных маленьких изменений.
Пользовательские команды
НАЗВАНИЕ
Обычный результат содержит строки следующего вида:
После каждой из таких строк идут все затронутые строки первого файла, предваренные символом ‘ ‘.
-b Игнорировать хвостовые пробелы (символы пробела и табуляции) и считать любые строки из пробелов совпадающими.
Следующие опции используются при сравнении каталогов:
Поддерживаются следующие операнды:
Если только один из файлов является каталогом, утилита diff будет применяться к другому файлу и к одноименному (имя которого соответствует последнему компоненту имени файла) с ним файлу в каталоге.
Пример 1: Пример использования команды diff.
Описание следующих переменных среды, влияющих на работу diff, см. на странице справочного руководства environ(5): LC_CTYPE, LC_MESSAGES, LC_TIME NLSPATH.
Команда возвращает следующие статусы выхода:
| 0 | Различий не найдено. | ||||||
| 1 | Различия найдены. | ||||||
| >1 | Произошла ошибка. |
| ТИП АТРИБУТА | ЗНАЧЕНИЕ АТРИБУТА |
| Доступен в пакете | SUNWesu |
| CSI | Включено |
ССЫЛКИ
Сообщение Missing NEWLINE в конце файла свидетельствует о том, что в последней строке соответствующего файла нет символа новой строки. Если в результате последние строки файлов получаются разными, они помечаются и выдаются, хотя на вид они кажутся одинаковыми.
Последнее изменение: 20 декабря 1996 года
Сравнение файлов в Linux с помощью diff
Сравнение файлов
Предположим у вас есть файл 1 следующего содержания
И файл 2 у которого первая строка пустая
сравнить их можно командой diff
В выводе команды diff содержится инструкция о том как из первого файла сделать второй.
После нулевой строки первого файла нужно добавить первую строку второго файла.
Другими словами: в начало первого файла нужно вставить первую (пустую) строку второго файла и тогда файлы станут одинаковыми
> означает второй файл. После должно быть содеражание строки, которую нужно вставить, но она в нашем случае пустая, поэтому ничего нет.
Как видите, так и произошло, потому что чтобы из первого файла получить второй нужно в самое начало первого файла добавить строку с текстом www.topbicycle.ru
1d0 3 у которого первая и вторая строки пустые а в третьей символ a
Подумайте самостоятельно, что будет если сравнить файлы 1 и 3. А также наоборот 3 и 1
0a1,2 означает, что в начало файла 1 нужно добавить первую и вторую строки файла 3
Если сравнить наоборот
1,2d0 3 нужно удалить строки 1 и 2 и тогда мы попадаем в начало файла 1
0 в конце можно понимать как строку по которой произойдёт выравнивание файлов.
Для примера создадим файл 4 у которого первая строка это символ a, вторая строка символ b
Добавим три пустые строки в середину и сохраним как файл 5
Чтобы из файла 4 получить файл 5 нужно после первой строки файла 4 добавить строки со второй по четвёртую файла 5
Здесь всё просто, попробуем наоборото
2,4d1 5 получить файл 4 нужно строки со второй по четвёртую в файле 4 удалить и тогда мы попадём на строку 1 файла 4
То есть в этом примере после удаления мы выровнялиьс по строке 1 а не по началу файла как в предыдущем примере.
Предположим у вас есть файл 1 следующего содержания
И пустой файл 2 сравнить их можно командой diff
1,3d0 2 и сравнить снова
2,3d1 websites.txt со списком сайтов
Скопируйте его командой
cp websites.txt newsites.txt
Убедиться, что файлы одинаковые пока что легко, можно даже выполнить
И понять, что ничего не изменилось.
Если файл слишком большой можно воспользоваться командой diff
diff websites.txt newsites.txt
Пока файлы идентичны вывод будет пустым
Добавьте новую запись в файл newsites.txt
echo https://www.andreyolegovich.ru >> newsites.txt
Команда diff теперь покажет место, в котором файлы различаются
diff websites.txt newsites.txt
3a4 означает, что различие найдено между третьей строкой первого файла и четвёртой строкой второго.
В данном случае четвёртой строки и первого файла просто нет
> https://www.andreyolegovich.ru это символы которых нет в первом файле
Внесите более мелкие изменения. Например удалим во втором файле www. перед heihei.ru
diff websites.txt newsites.txt
2c2 https://heihei.ru 3a4 > https://www.andreyolegovich.ru
diff находит все строки с различиями и выводит их. Поэтому если вы сделаете ещё какие-то изменения в той же строке, например добавите в конец /Spain/ принципиально ничего не изменится
diff websites.txt newsites.txt
2c2 https://www.heihei.ru/Spain/ 3a4 > https://www.andreyolegovich.ru
Если добавить несколько пустых строк
Будут показаны диапазоны с пустыми строками



