Наши партнеры

UnixForum





Библиотека сайта 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 вопросы в рамках нескольких статей, но все же все основные возможности и функции данной утилиты были так или иначе упомянуты в них.

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