Команда Unix для поиска строк, общих в двух файлах

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

Ответ 1

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

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

Здесь:

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

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

Ответ 2

Чтобы легко применить команду 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!

Ответ 3

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

Сравнение отсортированных файлов FILE1 и FILE2 по строкам.

Без параметров выведите трех столбцов. Колонка 1 содержит строки, уникальные для FILE1, столбец два содержат строки, уникальные для FILE2 и три столбца содержат строки, общие для обоих файлов.

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

Ответ 4

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

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

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

Ответ 5

Пока

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

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

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

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

Ответ 6

perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

На ограниченной версии 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 должен быть в том же порядке, что и исходные, то добавьте эту строку для того же порядка, что и file1:

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

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

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

Ответ 10

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


Объединив эти два ответа (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) и запустите его. Он примет все файлы, присутствующие в текущем рабочем каталоге, и сделает сравнение all-vs-all, оставив в файле match_lines результат.

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

  • Пропустить каталоги
  • Избегайте сравнения всех файлов два раза (file1 vs file2 и file2 vs file1).
  • Возможно, добавьте номер строки рядом с соответствующей строкой

Ответ 11

rm file3.txt

cat file1.out | while read line1
do
        cat file2.out | while read line2
        do
                if [[ $line1 == $line2 ]]; then
                        echo $line1 >>file3.out
                fi
        done
done

Это должно сделать это.