Команда Unix для поиска строк, общих в двух файлах - PullRequest
161 голосов
/ 17 декабря 2008

Я уверен, что однажды нашел команду unix, которая могла бы печатать общие строки из двух или более файлов, кто-нибудь знает ее название? Это было намного проще, чем diff.

Ответы [ 11 ]

192 голосов
/ 17 декабря 2008

Команда, которую вы ищете: comm. например: -

comm -12 1.sorted.txt 2.sorted.txt

Здесь:

-1 : исключить столбец 1 (строки уникальны для 1.sorted.txt)

-2 : исключить столбец 2 (строки уникальны для 2.sorted.txt)

57 голосов
/ 20 июля 2014

Чтобы легко применить команду comm к несортированным файлам, используйте замену процесса Bash :

$ bash --version
GNU bash, version 3.2.51(1)-release
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat > abc
123
567
132
$ cat > def
132
777
321

Таким образом, файлы abc и def имеют одну общую строку, одну с «132». Использование comm для несортированных файлов:

$ comm abc def
123
    132
567
132
    777
    321
$ comm -12 abc def # No output! The common line is not found
$

Последняя строка не выдала, общая линия не была обнаружена.

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

$ comm <( sort abc ) <( sort def )
123
            132
    321
567
    777
$ comm -12 <( sort abc ) <( sort def )
132

Теперь мы получили строку 132!

24 голосов
/ 12 октября 2014

Чтобы дополнить однострочник Perl, вот его awk эквивалент:

awk 'NR==FNR{arr[$0];next} $0 in arr' file1 file2

Это прочитает все строки из file1 в массив arr[], а затем проверит для каждой строки в file2, существует ли она уже внутри массива (т.е. file1). Найденные строки будут напечатаны в том порядке, в котором они указаны в file2. Обратите внимание, что для сравнения in arr используется вся строка от file2 в качестве индекса для массива, поэтому он будет сообщать только точные совпадения на целых строках.

24 голосов
/ 17 декабря 2008

Может быть, вы имеете в виду comm?

Сравнить отсортированные файлы FILE1 и FILE2 построчно.

Без опций выведите три столбца. Первый столбец содержит строки, уникальные для FILE1, столбец два содержит строки, уникальные для ФАЙЛ2 и третий столбец содержат строки, общие для обоих файлов.

Секретом поиска этой информации являются информационные страницы. Для программ GNU они намного более подробны, чем их man-страницы. Попробуйте info coreutils, и в нем будут перечислены все небольшие полезные утилиты.

18 голосов
/ 20 января 2015

Пока

grep -v -f 1.txt 2.txt > 3.txt

дает вам различия двух файлов (то есть в 2.txt, а не в 1.txt), вы можете легко сделать

grep -f 1.txt 2.txt > 3.txt

собрать все общие строки, которые должны обеспечить простое решение вашей проблемы. Если у вас есть отсортированные файлы, вы все равно должны взять comm. Привет!

8 голосов
/ 17 июля 2013
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
5 голосов
/ 14 августа 2016
awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2
4 голосов
/ 21 июля 2017

Если два файла еще не отсортированы, вы можете использовать:

comm -12 <(sort a.txt) <(sort b.txt)

и это будет работать, избегая сообщения об ошибке comm: file 2 is not in sorted order при выполнении comm -12 a.txt b.txt.

3 голосов
/ 20 марта 2016

В ограниченной версии Linux (например, QNAP (nas), над которой я работал):

  • связи не существовало
  • grep -f file1 file2 может вызвать некоторые проблемы, как сказал @ChristopherSchultz, и использование grep -F -f file1 file2 было действительно медленным (более 5 минут - не завершено - более 2-3 секунд с методом ниже для файлов размером более 20 МБ)

Итак, вот что я сделал:

sort file1 > file1.sorted
sort file2 > file2.sorted

diff file1.sorted file2.sorted | grep "<" | sed 's/^< *//' > files.diff
diff file1.sorted files.diff | grep "<" | sed 's/^< *//' > files.same.sorted

Если files.same.sorted должен быть в том же порядке, что и исходные, то добавить эту строку для того же порядка, что и файл1:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file1 > files.same

или, для того же порядка, что и файл2:

awk 'FNR==NR {a[$0]=$0; next}; $0 in a {print a[$0]}' files.same.sorted file2 > files.same
2 голосов
/ 08 ноября 2013

Просто для справки, если кто-то все еще ищет, как это сделать для нескольких файлов, см. Связанный ответ на Поиск совпадающих строк во многих файлах.


Сочетая эти два ответа ( ans1 и ans2 ), я думаю, что вы можете получить нужный вам результат без сортировки файлов:

#!/bin/bash
ans="matching_lines"

for file1 in *
do 
    for file2 in *
        do 
            if  [ "$file1" != "$ans" ] && [ "$file2" != "$ans" ] && [ "$file1" != "$file2" ] ; then
                echo "Comparing: $file1 $file2 ..." >> $ans
                perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' $file1 $file2 >> $ans
            fi
         done 
done

Просто сохраните его, дайте ему права на выполнение (chmod +x compareFiles.sh) и запустите его. Он примет все файлы, присутствующие в текущем рабочем каталоге, и выполнит сравнение «все против всех», оставив в файле «Match_Lines» результат.

Что нужно улучшить:

  • Пропускать каталоги
  • Старайтесь не сравнивать все файлы два раза (файл1 с файлом2 и файл2 с файлом1).
  • Возможно, добавьте номер строки рядом с соответствующей строкой
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...