Bash сравнить два файла
Команда Diff в Linux используется для сравнения содержимого двух файлов построчно, и если разница обнаружена, она также перечислит различия вместе с номерами строк. Команду Diff также можно использовать для сравнения содержимого двух каталогов.
Синтаксис команды diff:
Вывод команды diff может быть в следующем формате:
- Нормальный (по умолчанию)
- Контекст
- Унифицированный
В выводе команды diff используются следующие символы:
- a -> указывает, что что-то было добавлено
- c -> указывает, что какой-то текст был изменен
- d -> указывает, что какой-то текст был удален
По умолчанию вывод команды diff находится в нормальном формате, это означает, что если содержимое двух файлов идентично, то вывод не будет производиться, но мы получим приглашение.
В этой статье мы изучим команду Linux diff с различными практическими примерами,
Пример: 9) Перенаправление вывода команды diff в файл
Это все из этой статьи. Надеюсь, теперь вы лучше понимаете команду diff, рассмотрев приведенные выше примеры. Не стесняйтесь делиться своими отзывами и комментариями.
В былые времена, на Windows, для сравнения oracle-схем (читай баз) я удовлетворялся встроенным в Quest Software TOAD сравнивателем. Он был неплох, и со своей задачей справлялся. Но пересев в linux, меня ждало разочарование. Ни один из [и так небольшого количества] инструментов не предоставляет даже половины былого комфорта. А именно, элементарное сравнение и мёржинг двух файлов (DDL, SQL, любых исходников — не суть) по несколько тысяч строк в каждом, где каждый отформатирован по-своему а реальных изменений всего-ничего, становится натуральной пыткой.
Поняв тщетность попыток найти необходимый функционал в одном инструменте, я решил поискать костыли в виде сторонних инструментов. А именно — самостоятельные сравниловки и мёржиловки ([visual] compare and merging tools). Перебрав практически все популярные инструменты, выяснилось, что очень немногие (читай почти никто) умели пропускать в сравнении двух текстовых файлов символы конца строки.
Для наглядности, поясню на примере. Допустим у нас есть 2 файла, типично старый и новый.
nFunctionResult :=
orauser.pack_util.FGetNeededValue (
in_nSomeParam => somevalue
);
dbms_output.put_line( 'Function result: ' ||
nFunctionResult);
exception
when SOME_EXCEPTION THEN
orauser.pack_util.PReportError( 'SOME_EXCEPTION' );
when OTHERS THEN
orauser.pack_util.PReportError( 'OTHER exception' );
end ;
declare
nFunctionResult NUMBER(9);
begin
nFunctionResult := orauser.pack_util.FGetNeededValue (in_nSomeParam => somevalue);
dbms_output.put_line( 'Function result: ' ||nFunctionResult);
exception
when SOME_EXCEPTION THEN
orauser.pack_util.PReportError( 'SOME_EXCEPTION' );
when OTHERS THEN
orauser.pack_util.PReportError( 'OTHER' );
end ;
Как видно пытливым человеческим глазом, суть различий файлов ora1.sql и ora2.sql в одном лишь слове и разном форматировании, но их diff абсолютно нечитаем. Вот классический результат их сравнения:
Не улучшает ситуацию и ключ «положить на все пробелы» -w:
Но ближе всех по смыслу подошла утилитка коммандной строки dwdiff. Эта небольшая обёрточка вокруг diff выдаёт ровно то, что мне нужно — различия на уровне СЛОВ. Но и без ложки дёгтя не обошлось — вывод этой утилиты своеобразен и стандартных опций для приведения разницы в diff формат не имеет:
[bugman@localhost 1]$ dwdiff -P -i ora1.sql ora2.sql
declare
nFunctionResult NUMBER(9);
begin
nFunctionResult := orauser.pack_util.FGetNeededValue (in_nSomeParam => somevalue);
dbms_output.put_line('Function result: '||nFunctionResult);
exception
when SOME_EXCEPTION THEN
orauser.pack_util.PReportError('SOME_EXCEPTION');
when OTHERS THEN
orauser.pack_util.PReportError('OTHER [-exception-]');
end;
С другой стороны, это и не мудрено, ибо стандарнтный patch имеет уровень строки, а в каком виде выводить разницу двух файлов, если они различаются по-дифовски в каждой строке? Этим вопросом я озадачился и списался с автором сей утилиты, коммрадом G.P. Halkes, результатом переписки стал небольшой костыль:
Сей враппер позволяет пользоваться в том числе и с визуальными дифферами, типа kdiff3. Сам скриптик, отточенная версия которого скоро войдёт в состав dwdiff и будет распространятся вместе с ней на радость ленивым кодерам, но кому не терпится уже сейчас опробовать его в работе, никакой магии тут нет:
P. S. Безусловно у описываемой мною проблемы существуют и другие решения. Одно из них - натравить на сравниваемые исходники какой-нить автоформатер. Но мне пришлось отказатся от этого по следующим соображениям: 1) в коллективе выработался некий coding style guide, привести в соответствие с которым любой автоформатер дело не одного даже наверное дня, тратить на это время, чтобы потом разочароваться в выборе пока нет возможности; 2) если откинуть предыдущий пункт, и просто привести копии упоминаемых файлов в какой-нибудь единый формат только для сравнивания, появляется другая задача - как спроецировать найденные различия на оригиналы?
Иногда возникает необходимость сравнить несколько файлов между собой. Это может понадобиться при анализе разницы между несколькими версиями конфигурационного файла или просто для сравнения различных файлов. В Linux для этого есть несколько утилит, как для работы через терминал, так и в графическом интерфейсе.
В этой статье мы рассмотрим как выполняется сравнение файлов Linux. Разберем самые полезные способы, как для терминала, так и в графическом режиме. Сначала рассмотрим как выполнять сравнение файла linux с помощью утилиты diff.
Сравнение файлов Linux с помощью GUI
Существует несколько отличных инструментов для сравнения файлов в linux в графическом интерфейсе. Вы без труда разберетесь как их использовать. Давайте рассмотрим несколько из них:
Сравнение файлов diff
Утилита diff linux - это программа, которая работает в консольном режиме. Ее синтаксис очень прост. Вызовите утилиту, передайте нужные файлы, а также задайте опции, если это необходимо:
$ diff опции файл1 файл2
Можно передать больше двух файлов, если это нужно. Перед тем как перейти к примерам, давайте рассмотрим опции утилиты:
- -q - выводить только отличия файлов;
- -s - выводить только совпадающие части;
- -с - выводить нужное количество строк после совпадений;
- -u - выводить только нужное количество строк после отличий;
- -y - выводить в две колонки;
- -e - вывод в формате ed скрипта;
- -n - вывод в формате RCS;
- -a - сравнивать файлы как текстовые, даже если они не текстовые;
- -t - заменить табуляции на пробелы в выводе;
- -l - разделить на страницы и добавить поддержку листания;
- -r - рекурсивное сравнение папок;
- -i - игнорировать регистр;
- -E - игнорировать изменения в табуляциях;
- -Z - не учитывать пробелы в конце строки;
- -b - не учитывать пробелы;
- -B - не учитывать пустые строки.
Это были основные опции утилиты, теперь давайте рассмотрим как сравнить файлы Linux. В выводе утилиты кроме, непосредственно, отображения изменений, выводит строку в которой указывается в какой строчке и что было сделано. Для этого используются такие символы:
К тому же, линии, которые отличаются, будут обозначаться символом .
Вот содержимое наших тестовых файлов:
Теперь давайте выполним сравнение файлов diff:
diff file1 file2
В результате мы получим строчку: 2,3c2,4. Она означает, что строки 2 и 3 были изменены. Вы можете использовать опции для игнорирования регистра:
diff -i file1 file2
Можно сделать вывод в две колонки:
diff -y file1 file2
А с помощью опции -u вы можете создать патч, который потом может быть наложен на такой же файл другим пользователем:
diff -u file1 file2
Чтобы обработать несколько файлов в папке удобно использовать опцию -r:
diff -r ~/tmp1 ~/tmp2
diff -u file1 file2 > file.patch
Как видите, все очень просто. Но не очень удобно. Более приятно использовать графические инструменты.
Синтаксис команды diff
Команда diff имеет следующий синтаксис:
Команда diff сравнивает два файла построчно. При этом первый из файлов она считает нуждающимся в редактировании и приведении к виду второго файла. Второй файл для diff — образец для сравнения.
Поэтому в выводе команды даются указания, что и как нужно изменить, чтобы первый файл стал таким же, как второй.
Указания даются при помощи специальных символов:
- c — CHANGE — изменение, которое нужно внести в указанной строке первого файла
- d — DELETE — то, что нужно удалить в первом файле
- a — ADD — то, что нужно добавить в первый файл
Давайте рассмотрим несколько примеров использования команды diff.
1. Kompare
Kompare - это графическая утилита для работы с diff, которая позволяет находить отличия в файлах, а также объединять их. Написана на Qt и рассчитана в первую очередь на KDE. Кроме сравнения файлов утилита поддерживает сравнение каталогов и позволяет создавать и применять патчи к файлам.
Пример: 1) Сравните два файла с помощью команды diff
Предположим, у нас есть два файла aachen.txt и sydney.txt, и следующее содержимое этих файлов:
Давайте сравним содержимое этих файлов с помощью команды diff,
Приведенный выше вывод подтверждает, что оба файла идентичны. Давайте внесем некоторые изменения в aachen.txt, перепишем open source как « open-source ».
Теперь повторно запустите команду diff,
В выходных данных 1c1 указывает, что 1-я строка первого файла должна быть изменена, чтобы сделать оба файла идентичными.
Давайте откатим вышеупомянутое изменение и добавим новую строку « Arch Linux » в sydeny.txt в конце файла и снова запустим команду diff,
Давайте удалим «Arch Linux» и «Fedora» из sydney.txt, а затем попробуем сравнить эти файлы,
Вывод команды diff « 7d6 » указывает, что нам нужно удалить 7-ю строку в первом файле для синхронизации со вторым файлом в строке номер 6.
2. Meld
Это легкий инструмент для сравнения и объединения файлов. Он позволяет сравнивать файлы, каталоги, а также выполнять функции системы контроля версий. Программа создана для разработчиков и позволяет сравнивать до трёх файлов. Можно сравнивать каталоги и автоматически объединять сравниваемые файлы. Кроме того поддерживаются такие системы контроля версий, как Git.
Примеры использования команды patch
Предположим, у нас есть простой JavaScript-код в файле print_in_js.js, который выводит строку.
Наш коллега находит опечатку в строке № 3 и исправляет файл.
Когда файл исправлен и код работает корректно, наш коллега создает патч:
Давайте посмотрим содержимое патча:
Получив патч, мы применяем его:
И — вуаля! — наш код исправлен!
Пример: 4) Игнорировать регистр при сравнении файлов (-i)
По умолчанию команда diff чувствительна к регистру, и если вы хотите игнорировать чувствительность к регистру в команде diff, используйте параметр «-i», пример показан ниже,
Предположим, у нас есть следующее содержимое двух файлов
Запустите команду diff без каких-либо параметров,
Теперь запустите команду diff с параметром -i,
Как видно из вышеприведенного вывода, команда diff проигнорировала чувствительность к регистру, когда мы использовали параметр -i.
Примеры использования команды diff
Чтобы выяснить, являются ли файлы одинаковыми, команда diff дополняется флагом -s . В нашем примере содержимое файлов fileA и sameAsfileA совпадает.
А в следующем примере файлы имеют разный контент. Вывод команды diff говорит, что строки 11 и 14 в showList_v2.js нужно изменить, чтобы они совпадали со строками 11 и 13 в showList_v1.js.
Далее мы рассмотрим мой любимый способ использования команды diff — параллельный просмотр изменений. Для этого нужно применить флаг -y:
И последний пример — с объединенным выводом. Такой output часто используется как input для команды patch (ее мы тоже рассмотрим):
Вот еще несколько полезных флагов, которые можно применять с командой diff:
- -i — для игнорирования регистра. По умолчанию команда diff учитывает регистр.
- -w — для игнорирования пробелов в файле. По умолчанию пробелы тоже учитываются и могут считаться различием.
Пример: 8) Сравните два каталога с помощью команды diff
Предположим, у нас есть два каталога с именами lab01 и lab02, в них есть следующие файлы и подкаталоги
Давайте сравним эти два каталога, используя приведенную ниже команду diff,
- -q -> указывает команде diff сообщать только о разных файлах
- -r -> предписывает команде diff рекурсивно искать разницу в подкаталогах
Поскольку мы получаем пустой вывод, это означает, что оба каталога идентичны. Давайте удалим filed.txt от lab02 , а затем попытаться сравнить,
Приведенный выше вывод говорит, что filed.txt присутствует только в каталоге lab01.
Пример: 6) Игнорировать пробелы при сравнении файлов с помощью diff (-b)
Предположим, у нас есть два файла filea.txt и fileb.txt, в которых пробелы несовместимы , поэтому, если мы используем команду diff без какой-либо опции, она покажет разницу пробелов, даже если содержимое идентично, поэтому в таких случаях мы можем игнорировать несогласованные пробелы в команде diff с помощью опции -b , пример показан ниже,
Сравните файлы без какой-либо опции с помощью команды diff,
Теперь используйте параметр -b в приведенной выше команде diff
Если вы хотите игнорировать все пробелы во время сравнения с помощью команды diff, используйте параметр « -w ».
Пример: 7) Игнорировать пробелы в конце строки во время сравнения (-Z)
Если вы хотите игнорировать пробел в конце строки во время сравнения, используйте опцию « -Z ».
Используйте « -B » в команде diff, чтобы игнорировать все пустые строки во время сравнения,
Пример: 3) Вывод команды Diff в едином формате (-u)
Используйте опцию «-u» в команде diff, если вы хотите выводить результат в унифицированном формате, пример показан ниже,
Вышеупомянутый вывод в некоторой степени похож на контекстный формат, но в унифицированном формате вывод отображается в сжатой форме, здесь первые две строки указывают имена файлов вместе с датой и временем их изменения.
Три дефиса («-») представляют первый файл, а три символа «плюс» («+++») представляют второй файл, после двух знаков @ «-1,7» обозначает строки из 1-го файла, а «+1,7» обозначает строки варьируются от 2-го файла. Кроме того, символ (+ Core OS) указывает, что эту строку необходимо добавить в первый файл, а символ дефиса (-Fedora) указывает, что эту строку необходимо удалить из первого файла, чтобы сделать его идентичным второму файлу.
3. Diffuse
Diffuse - еще один популярный и достаточно простой инструмент для сравнения и слияния файлов. Он написан на Python 2. Поэтому в современных версиях Ubuntu программу будет сложно установить. Поддерживается две основные возможности - сравнение файлов и управление версиями. Вы можете редактировать файлы прямо во время просмотра.
4. KDiff3
KDiff3 - еще один отличный, свободный инструмент для сравнения файлов в окружении рабочего стола KDE. Он входит в набор программ KDevelop и работает на всех платформах, включая Windows и MacOS. Можно выполнить сравнение до трех файлов Linux или даже сравнить каталоги. Кроме того, есть поддержка слияния и ручного выравнивания.
5. TkDiff
Это очень простая утилита для сравнения файлов написанная на основе библиотеки tk. Она позволяет сравнивать только два файла, поддерживает поиск и редактирование сравниваемых файлов.
Пример: 5) Файлы отчетов идентичны командам (-ам) diff
Синтаксис команды patch
Изменения в коде происходят постоянно. Расшаривать отредактированные файлы после внесения каждого изменения нереально. Обычно разработчики расшаривают сами изменения в коде.
Использование патчей («заплаток») — самый безопасный способ делиться только лишь изменениями.
Давайте посмотрим, как работают патчи:
Выводы
В этой статье мы рассмотрели как выполняется сравнение файлов linux с помощью терминала, как создавать патчи, а также сделали небольшой обзор лучших графических утилит для сравнения файлов. А какие инструменты для сравнения используете вы? Напишите в комментариях!
помогите сделать быстрее, или раскритикуйте вдребезги мой нубовской подход, прошу толчек в нужном направлении.
P.S. если бы не нужно было вывыодить всю строку из файла 2 проблема думаю решилась бы с помощю
comm -2 file1 file2 > file3 но не факт :)
- Вопрос задан более трёх лет назад
- 2472 просмотра
Оценить 1 комментарий
нужно во втором файле найти строки (и вывести всю строку в файл) у которых совпадает $1 и $3 но другой $6
в первойм файле $6=q1 во втором $6=q1-q3
столбец $1 всегда начинается с 9
Это не описание, а какая-то ахинея, по которой можно написать сто разных программ.
Приведи лучше уменьшенные исходные файлы (по паре строк каждый) и файл с результатом, который должен из них получиться.
Укажите первым файлом тот, что поменьше.
первым проходом выделяем из второго файла все строки, в которых есть совпадения по первому столбцу, вторым проходом выделяем совпадения по третьему столбцу, третьим исключаем ненужное по 6-му столбцу.
если можно - примеры файлов по несколько сотен строк дайте мылом, попробую написать
Простите не совсем точно обяснил
в 1 файле 1 столбец уникальный таких записей милинон 3й столбец не уникальный на милион уникальных где то 2000(мешать нельзя, и во втором файле есть много записей $1 но с другими $3 и $6)
вот а теперь нужно взять вот это сочетание $1 и $3 найти его в 2 файле и отбросить те где $6=q1 а результат в файл
к сожелению поэтапность тут не поможет(((((
cat /tmp/file22.txt | awk -F"," '
эта команда какраз и делает то что вы предложили берет 1 и 3 столбцы из 1 файла и значение для 6 столбца и ищет их в файле 2
Строки с несовпадающим $6 вы уже выкинули.
Перегоняем оба файла в формат $1,$3, отбрасывая прочую информацию и убирая дубли.
Сортируем, находим пересечение этих файлов.
Перегоняем второй в формат $1,$3,$2,$4,$5,$6,$7 и сортируем.
На своем любимом языке программирования открываем этот файл (1) и файл пересечений (2), сравнивая текущую строку в файле (2) с началом текущей строки в файле (1).
Если они совпадают - выводим, переставив столбцы.
Если нет - читаем следующую строку из файла, строка в котором оказалась меньше другого (данные-то отсортированы).
В один проход получаем результат, никаких недель.
Огромное спасибо за идеи по решению, решил осваивать perl =)
Сергей спасибо вам . немного почитал переделал и вуаля готово)))
Adamos Руслан Федосеев и вам спасибо применил ваши советы для предварительной подготовки файла к запуску основного скрипта в других его вариациях (не представленно ниже)
а чем не подошел мой вариант с ассоциативными массивами? При использовании ассоциативных массивов, вам не нужно выполнять полный перебор, код выглядит гораздо меньше и более читабельным, ну и вообще быстрее работает, меньше памяти требует.
Ваш вариант мне очень понравился но он не работал, возможно я не совсем правильно понял как это работает
дело в том что мне нужно сравнить:
есть 2 файла в каждом 5 столбцов
мне нужно взять n-й елемент первого столбца сравнить его со всеми значениями первого столбца втогого файла
если да то тогда сравнить 3 если да то тогда сравнить 4 если нет тогда на печать
if ($a0==$a1 && $c0==$c1 && $d0==$d1) print
Если это можно сделать с помощю "ассоциативными массивами" будет очень круто но вот применил и
х на практике и данные неверные получаю
Та были использованы ассоциативные массивы.
То есть вместо числового индекса элемента, я использую значение первого столбца как индекс, и мне не нужно выполнять поиск по всем элементам - само значение элемента и есть индекс, и я сравниваю только 3 и 4 столбец, без поиска элементов.
А не работать оно может, если у вас в первом столбце не уникальные значения, то есть если они могут повторяться. Тогда да, будут перезаписываться и логика нарушается, и мой вариант нужно дорабатывать. Но если ваш код работает, то никаких проблем. Перл полезен чтобы затыкать дырки ), хотя я бы рекомендовал использовать более интуитивно-понятные имена переменных, иначе через 2-3 недели вы сами в нем не разберетесь.
Да, значения первого столбца не уникальные, болше того они повторяются раз на 5-10 милионов, значения 3 и 5 столбика тоже повторяются но чаще
по поводу названий масивов согласен у меня там коментарии стоят(чтобы не забыть) использую обезличивание потому как нужен скрипт шаблон для 6 похожих задач
как решить это с помощью ассоциативных массивов?
Добавить в начало порядковый номер строки и использовать его как индификатор строки?
прочитал мануалы и сделал с помощью ассоциативных массивов, обработка милиарда значений происходит в 4 раза быстрее))))
Photo by Ryan Stone on Unsplash
Представьте, что однажды утром вы просыпаетесь и обнаруживаете, чтоб ваши продакшен-системы «лежат» из-за бага, который только предстоит найти. Один из наихудших кошмаров, верно?
Также оказывается, что для восстановления системы вам нужно сравнить код в двух версиях. Давление растет, все вокруг паникуют (и это понятно).
К счастью, в Linux есть утилита под названием diff, которая вам поможет.
Итоги
Создавать и применять патчи при помощи команд patch и diff довольно просто.
Похожий подход применяется, когда вы пользуетесь системами контроля версий вроде Git или SVN. Знание основ (т. е. работы соответствующих команд Linux) поможет вам лучше понять работу систем контроля версий, а это важно для разработчиков.
Пример: 2) Вывод команды Diff в контекстном формате (-c)
Используйте опцию «-c» в команде diff для вывода вывода команды diff в контекстном формате. Пример показан ниже,
Первые две строки представляют имена файлов вместе с датой и временем их изменения, а три символа звездочки (« *** ») указывают на первый файл, а три символа дефиса (« — ») указывают на второй файл.
Только одиночный дефис «-» указывает на то, что строку необходимо удалить, а символ плюса «+» указывает на то, что строку необходимо добавить в файл. Если какая-либо строка не требует изменений, то перед ней стоит два пробела.
Что из себя представляет команда diff в Linux?
Сравнение файлов и поиск различий между ними — широко распространенная операция. Она особенно полезна, когда нужно сравнить сложный код или конфигурационные файлы.
Сравнивать вручную долго и тяжело, к тому же велика вероятность ошибок. Поэтому Linux предоставляет вам мощную встроенную утилиту под названием diff. Ее применение позволяет сэкономить время и силы.
В Linux также есть еще одна команда, которая отлично дополняет diff, — patch. Она позволяет применить изменения из одного файла в другом. В этой статье мы рассмотрим обе команды и их применение на практике.
Читайте также: