Как показать линии в общем (обратный diff)?

170

У меня есть ряд текстовых файлов, для которых я хотел бы знать общие линии, а не строки, которые отличаются между ними. Командная строка Unix или Windows в порядке.

Foo:

linux-vdso.so.1 =>  (0x00007fffccffe000)
libvlc.so.2 => /usr/lib/libvlc.so.2 (0x00007f0dc4b0b000)
libvlccore.so.0 => /usr/lib/libvlccore.so.0 (0x00007f0dc483f000)
libc.so.6 => /lib/libc.so.6 (0x00007f0dc44cd000)

бар:

libkdeui.so.5 => /usr/lib/libkdeui.so.5 (0x00007f716ae22000)
libkio.so.5 => /usr/lib/libkio.so.5 (0x00007f716a96d000)
linux-vdso.so.1 =>  (0x00007fffccffe000)

Таким образом, учитывая, что эти два файла выше, вывод желаемой утилиты будет сродни file1:line_number, file2:line_number == matching text (просто предложение, мне действительно все равно, какой синтаксис):

foo:1, bar:3 == linux-vdso.so.1 =>  (0x00007fffccffe000)

Спасибо.

Мэтт Уилки
источник
@ChristopherSchultz Моя ошибка. 1-я строка в 1-м примере должна соответствовать последней строке во 2-м примере. Спасибо, что поймали ошибку; меняется.
Мэтт Уилки
1
Еще один похожий вопрос с хорошими ответами: unix.stackexchange.com/questions/1079/…
MortezaE

Ответы:

210

На * nix вы можете использовать комм . Ответ на вопрос:

comm -1 -2 file1.sorted file2.sorted 
# where file1 and file2 are sorted and piped into *.sorted

Вот полное использование comm:

comm [-1] [-2] [-3 ] file1 file2
-1 Suppress the output column of lines unique to file1.
-2 Suppress the output column of lines unique to file2.
-3 Suppress the output column of lines duplicated in file1 and file2. 

Также обратите внимание, что важно отсортировать файлы перед использованием comm, как упомянуто в справочных страницах.

Дэн Лью
источник
3
comm [-1] [-2] [-3] file1 file2 -1 Подавить выходной столбец строк, уникальных для file1. -2 Подавить выходной столбец строк, уникальных для file2. -3 Подавить выходной столбец строк, дублированных в file1 и file2.
ojblass
@ojblass: добавил это в ответ.
Мэтт J
6
Я обнаружил, что важно, чтобы файлы были отсортированы перед использованием comm. Возможно, добавьте это к ответу.
Мэтт Уилки
11
краткий ответ на вопрос: комм -1 -2 file1 file2
greggles
6
Вы можете использовать это, если ваши файлы не отсортированы: комм -1 -2 <(сортировка filename1) <(сортировка filename2)
Кевин Уилер
56

Нашел этот ответ на вопрос, указанный как дубликат . Я считаю, что grep более удобен для администратора, чем comm, поэтому, если вы просто хотите, чтобы набор совпадающих строк (например, был полезен для сравнения CSV), просто используйте

grep -F -x -f file1 file2

или упрощенная версия fgrep

fgrep -xf file1 file2

Кроме того, вы можете использовать file2*для поиска и поиска строк общего с несколькими файлами, а не только два.

Некоторые другие удобные варианты включают

  • -n флаг для отображения номера строки каждой совпавшей строки
  • -c считать только количество совпадающих строк
  • -vотображать только те строки в файле2, которые отличаются (или используют diff).

Использование commбыстрее, но эта скорость достигается за счет необходимости сначала сортировать файлы. Это не очень полезно в качестве «обратного сравнения».

Ryder
источник
спасибо Райдер, это может быть более полезным, чем общение со многими. Вы должны сослаться на исходный ответ (в правой части навигации есть более полдюжины ссылок в Q; найти немного работы). Было бы также полезно узнать, насколько хорошо grep работает с не отсортированным или по-разному отсортированным вводом и может печатать соответствующие номера строк совпадений.
Мэтт Уилки
1
@mattwilkie Я почувствовал необходимость вернуться и уточнить использование -vфлага после того, как сам подскочил. Скажем, у вас есть два CSV-файла file1 и file2, и они имеют как перекрывающиеся, так и не перекрывающиеся строки. Если вы хотите, чтобы все и только неперекрывающиеся строки, использование fgrep -v file1 file2вернет только непересекающиеся строки в file2 и ни одну из дополнительных непересекающихся строк в file1 . Это может быть очевидным для некоторых, но лучше заявить об очевидном, чем о неправильной интерпретации риска. В этом конкретном случае сортировка файлов и их использование commпо-прежнему является лучшим выбором.
Райдер
1
Спасибо, что вернулись и разъяснили Райдеру. Особое внимание отмечается и ценится (все легко позволить старым вещам ускользнуть!). Я поменял принятый ответ, потому что коммуникатор, безусловно, является выбором сообщества, хотя лично я все еще использую его, когда сортировка нежелательна.
Мэтт Уилки
2
Еще одно осложнение при использовании grep: любая пустая строка в первом файле будет соответствовать каждой строке во втором файле. Убедитесь, что в file1нем нет пустых строк, иначе файлы будут выглядеть одинаково.
Кристофер Шульц
grep -Fxfэто для меня.
loxaxs
35

Здесь раньше спрашивали: команда Unix для поиска строк, общих в двух файлах

Вы также можете попробовать с Perl (кредит идет здесь )

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
ChristopheD
источник
1
Спасибо. Я хотел бы принять оба ответа, так как perl one liner является кроссплатформенным. Comm получает поклон, потому что это проще.
Мэтт Уилки
1
Отлично. Использование терминала Cygwin на Windows и commне было легко доступно. Это была идеальная альтернатива.
Qix - МОНИКА ПРОИЗОШЛА
3
Это не заботится о том, как строки упорядочены. Это точнее, чем комм.
ent8enmentnow
1
Объяснение здесь: stackoverflow.com/questions/17552789/…
Крис Кокнат
17

Я только что узнал команду comm из этого потока, но хотел добавить что-то дополнительное: если файлы не отсортированы, и вы не хотите трогать исходные файлы, вы можете передать выход команды sort. Это оставляет исходные файлы без изменений. Работает в bash, я не могу сказать о других оболочках.

comm -1 -2 <(sort file1) <(sort file2)

Это может быть расширено для сравнения вывода команды вместо файлов:

comm -1 -2 <(ls /dir1 | sort) <(ls /dir2 | sort)
Грег Мюллер
источник
9

Самый простой способ сделать это:

awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2

Файлы не должны быть отсортированы.

Гопу
источник
1
Это не похоже на большинство ответов здесь, поскольку позволяет восстанавливать исходные шаблоны. У меня есть два файла, построенные из одной и той же оболочки, с разным текстом, вставленным в нескольких точках. Этот ответ позволил мне восстановить упаковщик.
Лукас Гонце
1

Просто для информации, я сделал небольшой инструмент для Windows, делающий то же самое, что и «grep -F -x -f file1 file2» (так как я не нашел ничего эквивалентного этой команде в Windows)

Вот оно: http://www.nerdzcore.com/?page=commonlines

Использование "CommonLines inputFile1 inputFile2 outputFile"

Исходный код также доступен (GPL)

Зивилин Бэйн
источник
1

В Windows вы можете использовать скрипт Powershell с CompareObject

compare-object -IncludeEqual -ExcludeDifferent -PassThru (get-content A.txt) (get-content B.txt)> MATCHING.txt | Out-Null #Find Matching Lines

CompareObject:

  • IncludeEqual без -ExcludeDifferent: все
  • ExcludeDifferent без -InclueEqual: ничего
Сорокопут
источник