Библиотека сайта rus-linux.net
Построчное сравнение текстовых файлов в Linux с помощью утилиты diff - часть 2
Оригинал: How to do line-by-line comparison of files in Linux using diff command - Part II
Автор: Himanshu Arora
Дата публикации: 2 января 2017 г.
Перевод: А.Панин
Дата перевода: 13 февраля 2017 г.
В первой статье серии мы обсудили основные вопросы, связанные с использованием утилиты diff, включая принцип ее работы, а также методику разбора ее вывода. Хотя данная утилита с интерфейсом командной строки и предполагает высокий уровень вхождения, вам стоит научиться работать с ней, особенно в том случае, если ваша повседневная работа связана с обработкой файлов на машинах, работающих под управлением Linux без графического интерфейса.
Предполагая, что вы уже умеете работать с утилитой diff, в данной статье я предлагаю обсудить различные параметры командной строки этой утилиты на основе простых для понимания примеров.
Но перед тем, как перейти к рассмотрению параметров командной строки утилиты, следует упомянуть о том, что все примеры из данной статьи были протестированы в системе Ubuntu 14.04 с Bash версии 4.3.11(1) и diff версии 3.3.
Параметры командной строки утилиты diff
1. Вывод сообщения об идентичности файлов
По умолчанию в случае установления факта идентичности файлов утилита diff не выводит никаких сообщений.
$ diff file1 file2 $
Но существует специальный параметр командной строки (-s
), в случае использования которого данная утилита будет сообщать об идентичности файлов:
$ diff -s file1 file2 Файлы file1 и file2 идентичны
2. Копируемый и унифицированный контексты вывода
Утилита diff поддерживает, по сути, два различных формата вывода. Копируемый контекст вывода (copied context) активируется с помощью параметра командной строки -c
, а унифицированный контекст (unified context) - с помощью параметра командной строки -u
. Это пример первого первого формата вывода:
$ diff -c file1 file2 *** file1 2016-12-29 09:36:47.175597647 +0530 --- file2 2016-12-29 09:19:55.799558326 +0530 *************** *** 1,3 **** Hi ! Helllo Bye --- 1,3 ---- Hi ! Hello Bye
Очевидно, что в случае использования копируемого контекста вывода отличающиеся строки маркируются с помощью символа восклицательного знака ("!"
).
А это пример унифицированного контекста вывода:
$ diff -u file1 file2 --- file1 2016-12-29 09:36:47.175597647 +0530 +++ file2 2016-12-29 09:19:55.799558326 +0530 @@ -1,3 +1,3 @@ Hi -Helllo +Hello Bye
"+"
и "-"
перед строками соответствуют различиям в файлах: с помощью символа "-"
маркируются строки из файла с именем file1, отсутствующие в файле с именем file2, а с помощью символа "+"
- строки из файла с именем file2, которые должны быть добавлены в файл с именем file1.
3. Вывод сценария для текстового редактора ed
Утилита diff также может выводить последовательности команд, которые, в свою очередь, могут использоваться текстовым редактором ed
для преобразования оригинального файла (в наших примерах с именем file1) в новый файл (с именем file2). Вы можете получить такой вывод следующим образом.
Предположим, что файлы с именами file1 и file2 имеют следующие различия:
$ diff file1 file2 2c2 < Helllo --- > Hello
Теперь используем параметр командной строки -e
для генерации вывода, понятного текстовому редактору ed
, после чего перенаправим этот вывод в отдельный файл:
diff -e file1 file2 > out
В данном случае в файле будет сохранен следующий вывод утилиты:
2c Hello .
После этого вам придется самостоятельно добавить команду "w"
в конец этого файла:
2c Hello . w
Теперь вы можете выполнить следующую команду:
ed - file1 < out
В результате файлы с именами file1 и file2 станут идентичными:
$ diff file1 file2 $
Если вас интересует дополнительная информация, связанная с данной функцией утилиты, вы можете перейти по
4. Генерация вывода в двух столбцах
Обычно diff генерирует вывод следующего формата:
$ diff file1 file2 2c2 < Helllo --- > Hello
Но существует специальный параметр командной строки (-y
), который сообщает утилите о необходимости вывода данных в двух отдельных столбцах. А это пример такого вывода:
$ diff -y file1 file2 Hi Hi Helllo | Hello Bye Bye
Очевидно, что при использовании данного формата вывода символ "|"
используется для маркировки отличающихся строк.
5. Сокрытие идентичных строк
Если вы внимательно рассмотрите вывод из предыдущего примера (из расположенного выше раздела 4), вы обнаружите, что при использовании параметра командной строки -y
утилита diff выводит не только измененные, но и идентичные строки обрабатываемых файлов. В том случае, если вам нужно убрать идентичные строки из вывода, вы можете воспользоваться параметром --suppress-common-lines
.
$ diff -y --suppress-common-lines file1 file2 Helllo | Hello
6. Вывод имен функций языка C, содержащих измененный код
При использовании утилиты diff для сравнения двух файлов исходного кода на языке C может использоваться специальный параметр (-p
), который сообщает утилите о необходимости вывода имен функций, в коде которых были обнаружены изменения. Например, предположим, что требуется сравнить два следующих файла исходного кода на языке C:
Файл с именем file1.c:
#include <stdio.h> void compare(float x, float y) { if(x == y) // некорректный способ сравнения { printf("\n РАВНЫ \n"); } } int main(void) { compare(1.234, 1.56789); return 0; }
Файл с именем file2:
#include <stdio.h> void compare(float x, float y) { if(x == y) { printf("\n РАВНЫ \n"); } } int main(void) { compare(1.234, 1.56789); return 0; }
Это результат обычного сравнения этих файлов:
$ diff file1.c file2.c 5c5 < if(x == y) // некорректный способ сравнения --- > if(x == y)
А это результат сравнения тех же файлов с использованием параметра -p
:
$ diff -p file1.c file2.c *** file1.c 2016-12-29 11:45:36.587010816 +0530 --- file2.c 2016-12-29 11:46:39.823013274 +0530 *************** *** 2,8 **** void compare(float x, float y) { ! if(x == y) // некорректный способ сравнения { printf("\n РАВНЫ \n"); } --- 2,8 ---- void compare(float x, float y) { ! if(x == y) { printf("\n РАВНЫ \n"); }
Очевидно, что в случае использования параметра командной строки -p
diff генерирует более подробный вывод с маркировкой измененных строк с помощью символа восклицательного знака ("!"
).
7. Рекурсивное сравнение содержимого поддиректорий
Утилита diff также позволяет осуществлять рекурсивное сравнение содержимого поддиректорий, но этот режим работы не активирован по умолчанию. Я подразумевал, что при использовании данной команды:
$ diff diff-files/ second-diff-files/ diff diff-files/file1 second-diff-files/file1 1c1 < Hi --- > i diff diff-files/file2 second-diff-files/file2 2c2 < Hello --- > ello
утилита diff будет осуществлять сравнение лишь файлов из директорий верхнего уровня, но в случае использования параметра -r
(активирующего режим рекурсивного сравнения файлов) будет осуществляться сравнение даже тех файлов, которые находятся в поддиректориях:
$ diff -r diff-files/ second-diff-files/ diff -r diff-files/file1 second-diff-files/file1 1c1 < Hi --- > i diff -r diff-files/file2 second-diff-files/file2 2c2 < Hello --- > ello diff -r diff-files/more-diff-files/file1 second-diff-files/more-diff-files/file1 1c1 < Hi --- > i diff -r diff-files/more-diff-files/file2 second-diff-files/more-diff-files/file2 2c2 < Hello --- > ello
8. Обработка отсутствующих файлов как пустых
Утилита diff также поддерживает параметр, с помощью которого вы можете сообщить ей о том, что следует рассматривать отсутствующие файлы как пустые. Если вы сравните файлы с именами file1 и file3 (причем последнего файла не существует), по умолчанию diff выведет сообщение об ошибке:
$ diff file1 file3 diff: file3: Нет такого файла или каталога
В этом нет ничего плохого; по сути, данное поведение является вполне обоснованным. Но бывают случаи, когда необходимо избежать вывода сообщений об ошибках (возможно, при использовании diff в рамках сценариев командной оболочки), в которых вы можете воспользоваться параметром -N
для обработки отсутствующих файлов как пустых и продолжения сравнения файлов.
$ diff -N file1 file3 1,5d0 < Hi < < Helllo < < Bye
Заключение
Если вы внимательно прочитали обе статьи серии и самостоятельно повторили все рассмотренные в них примеры команд, то вполне можно сказать, что вы овладели всеми основными навыками работы с рассматриваемой утилитой. Конечно же, мы не смогли бы обсудить все связанные с diff вопросы в рамках нескольких статей, но все же все основные возможности и функции данной утилиты были так или иначе упомянуты в них.
Если вы хотите узнать немого больше о данной утилите, вы всегда можете обратиться к ее