- Сравнение файлов в Linux – утилита diff
- Основные возможности утилиты diff
- Синтаксис команды diff и её основные опции
- Использование команды diff
- Создание патчей (заплаток) с помощью утилиты diff
- Заключение
- HuMan: diff
- Команда diff без опций
- Опция -с: Контекстный формат
- Опция —u: Унифицированный формат
- Опция -y или —side-by-side (бок-о-бок) Сравнительный формат
- —left-column (левая колонка)
- —suppress-common-lines
- Опция -e или —ed
- Опция -f или —forward-ed (прямой ed)
- Опция -n или —rcs
- Опция -D NAME
- Сравнение каталогов
- Опция -s или —report-identical-files
- Опция -r или —recursive
- Опция -N или —new-file
- Опция -P или —unidirectional-new-file
- Опция -x ОБРАЗЕЦ или —exclude=ОБРАЗЕЦ
- Опция -S ИМЯ_ФАЙЛА или —starting-file=ИМЯ_ФАЙЛА
- Форматирование вывода команды diff
- Опция -t или —expand-tabs
- Опция -T или —initial-tab
- Опция -l или —paginate
- Регулировка производительности команды diff
- Опция -d или —minimal
- Опция -H или —speed-large-files
- Опция —horizon-lines=ЧИСЛО_СТРОК
- Сравнение трех файлов: Команда diff3
- Интерактивное объединение файлов при помощи команды sdiff
- Правка файлов при помощи команды patch
- Все опции команды diff
Сравнение файлов в Linux – утилита diff
Очень часто возникают ситуации, когда необходимо сравнить содержимое двух или нескольких текстовых файлов. Например, для системных администраторов важно знать о конкретных различиях в конфигурации обслуживаемых систем. Программистам и разработчикам не менее важно быстро выявить различия в коде проектов, а также быстро создать патч, отражающий соответствующие изменения между двумя файлами или разными версиями одного. Это лишь самый распространённый перечень ситуаций, когда использование специализированных утилит для сравнения содержимого файлов приходится очень кстати и экономит кучу времени. Одной из таких утилит в системах Linux является diff – о ней и пойдёт речь в данной статье.
Основные возможности утилиты diff
Главное и, наверное, самое ценное преимущество diff в том, что эта утилита прекрасно работает через интерфейс командной строки. Вот почему она довольно популярна среди системных администраторов. Однако, это обстоятельство вполне закономерно объясняет и имеющийся у diff недостаток — работа с ней недостаточно наглядна, а для новичков довольно сложна.
В отличие от других аналогичных утилит, которые можно использовать исключительно в графической среде, diff прекрасно справляется со своими задачами в командной оболочке. Ну а некоторые неудобства, связанные с восприятием выводимых результатов работы утилиты — это в большинстве случаев, всего лишь недостаток пользовательского опыта работы как в командной оболочке, так и с самой утилитой diff. Стоит ещё раз отметить, что порог вхождения у неё для новичков действительно, довольно высок.
Утилита diff принимает на вход имена файлов, которые необходимо построчно сравнить, а также набор опций, управляющих режимами работы самой утилиты. В официальном руководстве (доступном по команде man diff) можно получить информацию о всех доступных для diff опциях. В данной же статье описываются лишь основные и часто используемые опции, а также простые и наглядные приёмы использования программы.
Синтаксис команды diff и её основные опции
Правила использования утилиты diff задаются командой, имеющей следующий синтаксис:
Здесь в качестве [FILES] задаются через пробел имена файлов для сравнения. [OPTION] определяет опции работы команды, основные из которых приведены в следующей таблице:
Опция | Значение |
-q, —brief | Выводит только различия файлов. |
-s | Выводит различия только при полном совпадении файлов. |
-c, -C | Выводит количество совпадающих строк. |
-u, -U | Выводит количество отличающихся строк. |
-y, —side-by-side | Выводит содержимое в столбцах для сравнения «бок о бок». |
-l, —paginate | Постраничный вывод с поддержкой перелистывания. |
-r, —recursive | Рекурсивное сравнение всех файлов в подкаталогах. |
-i, —ignore-case | Игнорировать регистр символов. |
-b, —ignore-space-change | Игнорировать изменения в изменении пробелов. |
-w, —ignore-all-space | Игнорировать все пробелы. |
-B, —ignore-blank-lines | Игнорировать пустые строки. |
-Z, —ignore-trailing-space | Игнорировать пробелы в конце строк. |
Перед тем, как использовать утилиту diff на практике, нужно разобраться с форматом вывода результатов сравнения. Вывод команды diff представляет собой последовательность инструкций, которые необходимо выполнить, чтобы файлы стали идентичными. Эти инструкции строятся на следующих обозначениях:
- a – добавление строки;
- d – удаление строки;
- c – изменение строки.
Вывод, например, может быть таким:
Здесь запись «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.
Источник
HuMan: diff
Команда diff служит для выявления различий между двумя файлами или всеми соответствующими файлами в двух директориях. Понятно, что применять команду имеет смысл только в случаях, когда исследуемые файлы или директории весьма схожи по содержанию.
Маны команды diff ограничивапются перечислением опций команды, поэтому для ее освоения пришлось провести увлекательное расследование.
Команда diff без опций
И запустим команду:
Попробуем разобраться с выводом команды. Выражение » > крыса» явно означает, что в правом (т.е. втором) файле есть лишнее слово: «крыса». Сложнее расшифровать выражение 1a2. Поскольку «крыса» вторая строка второго файла, то логично предположить, что цифра 2 означает номер строки, различной в сравниваемых файлах. Проверим предположение, поместив «крысу» на 4 строку:
Так и есть, отличается 4 строка второго файла. Появились и мысли насчет первой цифры, а также буквы «a».
Я понял это так:
1. Если считать эталонным первый файл, то 3 означает строку первого файла, после которой добавлена строка «крыса», являющаяся 4 строкой второго файла. Буква «a», по-видимому, означает первую букву в английском слове «added» (добавлено).
2. Если считать эталонным второй файл, то команда diff подсказывает, что надо сделать, дабы превратить первый файл во второй. Надо после третьей строки первого файла добавить (add) четвертую строку второго файла. Тогда файлы станут одинаковыми по содержанию.
Посмотрим, что произойдет, если мы поменяем сравниваемые файлы местами — первым поставим больший файл cot2.txt, а вторым меньший cot.txt:
Номера строк поменялись зеркально, что не удивительно, так как аналогично поменялось и расположение сравниваемых файлов. А вот буква «a» сменилась буквой «d». Рискнем предположить, что это первая буква слова «delete» — удалить. Итак, если удалить четвертую строку первого файла, то файлы станут одинаковыми. Цифра три в правой части выражения 4d3, вероятно, показывает, после какой строки второго файла следует различие в тексте файлов.
Осталось рассмотреть случай, когда в сравниваемых файлах одинаковое число строк. Давайте слегка изменим файл 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:
Здорово! Получилось, что мы не убрали кота из первого файла, а добавили во второй! Явно здесь первый файл служит эталоном. Чтобы убедиться в этом, восстановим кота в первом файле и уберем во втором:
Ну и ну! Нет, эталоном здесь и пахнет. Чтобы понять этот вывод, нужно сильно напрячься. В первом файле, где «кот» есть, почему-то значится «- кот». Вероятно, нужно убрать кота, чтобы строки стали одинаковы. Но почему же тогда на восьмой строке второго файла, где живет «крыса», значится «+ крыса»? В конце концов, я нашел такое объяснение:
Да-а, к этому формату нужно привыкнуть. Впрочем, есть еще унифицированный формат.
Опция —u: Унифицированный формат
Унифицированный формат по умолчанию не выводит строк контекста:
Присмотревшись и вдумавшись, можно понять следующее:
1. В заголовке сказано, что минусами помечены строки из первого файла, а плюсами — из второго.
2. Формат даты такой же, как у контекстного формата.
3. Диапазоны строк указаны для обоих файлов и отмечены знаками двойной «собаки».
4. Слова, общие для двух файлов ничем не отмечены (или, если хотите, отмечены пробелом).
5. Знаком минус помечены строки, которые есть только в первом файле, как бы изъятые из первого файла, если считать его эталонным.
6. Знаком плюс помечены строки, которых нет в первом файле, как бы добавленные к нему.
Не знаю как вам, но мне этот формат кажется наиболее понятным.
Используя опцию -U число_строк (—unified=число_строк), можно просматривать нужное число строк контекста. Я этого делать не стану, так как мои примерные файлы слишком короткие для этого. Проделайте этот опыт самостоятельно с файлами подлиннее.
Опция -y или —side-by-side (бок-о-бок) Сравнительный формат
Этот формат команды diff выдает две колонки текста, что наиболее наглядно. По умолчанию длина строки 130 символов, что хорошо для длинных строк, для статьи же неудобно. Поэтому я сразу применю опцию -W 25, которая задаст ширину колонки в 25 символов.
Между двумя колонками текста находится узкая колонка условных обозначений. Эти обозначения могут быть следующими:
Пробел Соответствующие строки эквивалентны. Это означает, что либо они одинаковые, либо различие игнорировано из-за одной из опций ‘—ignore’ .
‘|’ Соответствующие строки разные, и либо обе приведены полностью, либо обе не полностью.
‘\’ Соответствующие строки разные, первая строка приведена не полностью.
‘/ ‘ Соответствующие строки разные, вторая строка приведена не полностью.
‘ ‘ Строка содержится только во втором файле.
‘(‘ Строка содержится только в первом файле, но различие игнорируется.
‘)’ Строка содержится только вo втором файле, но различие игнорируется.
У опции -y есть, в свою очередь, несколько опций (или под-опций)
—left-column (левая колонка)
По-моему, все кристально ясно, может быть, я начинаю привыкать к этой команде?
Заметим в скобках, что опции —right-column (правая колонка) не существует.
—suppress-common-lines
Жаль, что эта опция не может быть применена вместе с опцией —left-column, добавление которой никак не влияет на вывод команды.
Опция -e или —ed
Мы теперь достаточно знаем о синтаксисе команды diff, чтобы и без редактора понять, что означает этот вывод.
1. Инструкции показывают, как превратить первый файл во второй.
2. «8a крыса » означает добавить после восьмой строки строку «крыса «.
3. «5c бизон» означает заменить пятую строку строкой «бизон».
4. 1d значит удалить первую строку.
Однако, при желании, мы можем воспользоваться редактором ed для превращения файла cot.txt в файл cot2.txt.
Для этого сначала перенаправим вывод команды diff -e cot.txt cot2.txt в файл ed.script, который будет автоматически создан в рабочей директории:
Затем запустим следующую конструкцию:
и проверим результат:
Полагаю, что «заклинание» в командной строке требует некоторого пояснения:
1. Применен программный канал, символом которого служит вертикальная черта (|). Вывод левой части канала служит вводом для правой части (команды ed — cot.txt ).
2. Выражение в скобках в левой части программного канала, означает последовательное выполнение двух команд: cat ed.script и echo w , а знак && между ними означает логическое «и». Благодаря этому знаку вывод обеих команд объединяется:
Мы видим уже знакомый нам скрипт и приписанную командой echo в последней строке букву «w», которая служит командой редактора ed.
3. В правой части программного канала команда ed — cot.txt . Благодаря дефису редактор ed принимает стандартный ввод в качестве командного скрипта. Команды, сгенерированные программой diff -e, изменяют содержимое файла cot.txt, а команда w заставляет переписать этот файл с учетом изменений.
Не спрашивайте меня, почему все это так, и как можно иначе, сейчас не время рассматривать работу редактора ed — это тема отдельного исследования.
Важен факт, что файл cot.txt превратился (по своему содержанию, а не по названию) в файл cot2.txt.
Опция -f или —forward-ed (прямой ed)
Опция -n или —rcs
Опция -D NAME
Как уже понятно читателю, команда diff создана программистами и для программистов, отсюда и изобилие различных форматов вывода. Ведь при написании программ чрезвычайно важно сличить разные варианты одной и той же программы, чтобы найти ошибки и разночтения.
Описываемая опция позволяет производить слияние двух файлов — текстов на языке программирования Си. Результат работы ‘diff’ в этом формате будет содержать все строки обоих файлов. Строки общие для файлов отображаются только один раз; разные части разделяются с помощью директив препроцессора Cи ‘#ifdef NAME’ или ‘#ifndef NAME’, ‘#else’, и ‘#endif’. При компиляции, таким образом, можно выбирать какую версию использовать, определяя или оставляя неопределенным макрос NAME. Аргумент NAME — это идентификатор, который будет использовать препроцессор Cи в директивах ‘#ifdef’ и ‘#ifndef’.
Так как я не программист и далек от языка Си, то на этом закончу описание этой важной опции. Она имеет множество суб-опций, и прочих особенностей. Интересующихся отсылаю к переведенному на русский язык руководству .
Сравнение каталогов
Создадим два каталога: dir1 и dir2.
Сравним две директории:
Без опций команда diff не упоминает о файлах с одинаковым содержимым (a-file и c-file), указывает различия в файле b-file, и сообщает о наличие лишнего файла в директории dir2.
Опция -s или —report-identical-files
Очень подробно и понятно.
Опция -r или —recursive
С опцией -r команда diff будет сравнивать соответствующие файлы в дереве каталогов, пока не доберется до последнего файла.
Опция -N или —new-file
Однако с опцией -N, команда diff «сделает вид», что пустой файл с тем же именем существует и в первом каталоге, и произведет сравнение содержимого этих файлов, то есть фактически выведет содержимое лишнего файла.
Опция -P или —unidirectional-new-file
Опция -x ОБРАЗЕЦ или —exclude=ОБРАЗЕЦ
Файл a-file был проигнорирован.
Необходимо заметить, что, при применении метасимволов, ОБРАЗЕЦ следует брать в одинарные кавычки.
Были проигнорированы все файлы, имена которых начинаются с букв «a» и «c».
Опцию -x можно использовать несколько раз в одной команде:
Если необходимо многократно использовать опцию -x, то можно составить файл ИМЯ_ФАЙЛА в который и поместить все необходимые ОБРАЗЦЫ по одному на строку. Затем, при помощи опции -X ИМЯ_ФАЙЛА или —exclude-from=ИМЯ_ФАЙЛА заставить команду diff считывать ОБРАЗЦЫ из созданного файла:
Опция -S ИМЯ_ФАЙЛА или —starting-file=ИМЯ_ФАЙЛА
Форматирование вывода команды diff
Опция -t или —expand-tabs
Опция -T или —initial-tab
Опция -l или —paginate
Регулировка производительности команды diff
Опция -d или —minimal
Опция -H или —speed-large-files
Опция —horizon-lines=ЧИСЛО_СТРОК
Данная опция запрещает команде diff отбрасывать ЧИСЛО_СТРОК, в начале и в конце файлов, что дает команде больше возможностей для поиска минимального результата. Понятно, что это замедляет работу команды.
Сравнение трех файлов: Команда diff3
Каждое различие отмечено знаком ====. Если различие касается всех трех файлов, то знак не меняется, если различие относится только к двум файлам, то к знаку добавляются цифры 1, 2 или 3, показывающие какой из трех файлов имеет данное отличие. Буквенные обозначения такие же, как в команде diff.
Команда diff3 имеет свои особенности, свойства и опции, которые в этой статье рассмотрены не будут. Интересующихся отсылаю к подробному руководству на русском языке.
Можно представить себе также команды diff4, diff5 и так далее, но практически такая необходимость возникает редко, да и формат вывода станет весьма громоздким.
Интерактивное объединение файлов при помощи команды sdiff
Правка файлов при помощи команды patch
Сначала нужно сравнить два файла при помощи diff и записать результаты в файл patch.file:
Затем применить команду patch:
Пользуясь инструкциями из файла patch.file команда patch перепишет текст файла cot.txt таким образом, что он станет идентичным тексту файла cot2.txt.
При этом первоначальный текст файла cot.txt будет утерян. Чтобы этого не происходило, следует применять опцию -b (backup).
Тогда программа patch создаст резервную копию файла cot.txt, а сам файл перепишет.
Команда patch «понимает» различные форматы вывода команды diff и автоматически определяет их. Эта команда также имеет немало опций и форматов, которые здесь рассмотрены не будут. Их описание можно найти в упомянутом уже несколько раз руководстве (на русском языке).
Все опции команды diff
—ignore-file-name-case Игнорирует разницу между строчными и заглавными буквами при сравнении файлов.
—no-ignore-file-name-case Учитывает разницу между строчными и заглавными буквами при сравнении файлов.
-E —ignore-tab-expansion Игнорирует изменения, связанные с табуляцией.
-b —ignore-space-change Игнорирует изменения в количестве пробелов.
-w —ignore-all-space Игнорирует все пробелы
-B —ignore-blank-lines Игнорирует изменения, связанные с полностью пустыми строками.
-I РЕГУЛЯРНОЕ_ВЫРАЖЕНИЕ —ignore-matching-lines=РЕГУЛЯРНОЕ_ВЫРАЖЕНИЕ Игнорирует изменения в строках, полностью соответствующих регулярному выражению.
-a —text Считает все файлы текстовыми
-c -C число_строк —context=число_строк Выводит число_строк контекста (по умолчанию 3)
-u -U число_строк —unified=число_строк Выводит число_строк контекста (по умолчанию 3)
—label LABEL Использует LABEL вместо имени файла
-p —show-c-function Сообщает какая функция языка Си затронута каждым отличием
-F РЕГУЛЯРНОЕ_ВЫРАЖЕНИЕ —show-function-line=РЕГУЛЯРНОЕ_ВЫРАЖЕНИЕ Показывает последнюю строку, соответствующую РЕГУЛЯРНОМУ_ВЫРАЖЕНИЮ
-q —brief Сообщает только различны ли файлы
-e —ed Выдает скрипт для редактора ed.
—normal Выводит нормальный формат.
-n —rcs Выводит формат RCS.
-y —side-by-side Выводит сравнительный (бок-о-бок) формат.
-W количество_символов —width=количество_символов Задает ширину колонки вывода (по умолчанию 130 символов)
—left-column Подавляет вывод правой колонки.
—suppress-common-lines Подавляет вывод одинаковых строк
-D NAME —ifdef=NAME Задает объединенный формат вывода ‘#ifdef’, в соответствии с макросом препроцессора NAME.
-l —paginate Пропускает результаты работы через программу pr для разбивки на страницы.
-t —expand-tabs Заменяет табуляцию на пробелы при выводе, для сохранения выравнивания по табуляции во входных файлах.
-T —initial-tab Заменяет на табуляцию пробелы перед текстом строки в нормальном или контекстном формате. Благодаря этому выравнивание по табуляции в строках выглядит нормально.
—tabsize=число_символов Табуляция пропускает число_символов (по умолчанию 8)
-r —recursive При сравнивании каталогов, рекурсивно сравнивает все найденные подкаталоги.
-N —new-file При сравнении каталогов, если файл найден только в одном каталоге, считает, что он находится и во втором, но является пустым.
—unidirectional-new-file При сравнении каталогов, если файл находится только в одном каталоге из двух, считает что он находится и в первом, но является пустым.
-s —report-identical-files Сообщает об одинаковых файлах.
-x ОБРАЗЕЦ —exclude=ОБРАЗЕЦ При сравнивании каталогов, игнорирует файлы и подкаталоги, имена которых начинаются с ОБРАЗЦА
-X FILE —exclude-from=FILE При сравнивании каталогов, игнорирует файлы и подкаталоги, соответствующие ОБРАЗЦАМ, содержащимся в файле FILE.
-S FILE —starting-file=FILE При сравнивании каталогов начинает с файла FILE.
—from-file=FILE1 Сравнивает FILE1 со всеми операндами. FILE1 может быть директорией.
—to-file=FILE2 Сравнивает все операнды с FILE2. FILE2 может быть директорией.
—horizon-lines=ЧИСЛО_СТРОК Не дает отбрасывать последние ЧИСЛО_СТРОК строк начала и первые ЧИСЛО_СТРОК конца файла.
-d —minimal Изменяет алгоритм, возможно находя меньший набор изменений. Это замедляет ‘diff’ (иногда очень сильно).
—speed-large-files Использует эвристику для быстрой обработки больших файлов, имеющих много рассеянных маленьких изменений.
-v —version Выводит номер версии ‘diff’.
Источник