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

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

11 ответов


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

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

здесь:

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

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


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

$ 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!


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

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

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

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


чтобы дополнить Perl one-liner, вот его awk эквивалентны:

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

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


пока

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

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

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

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


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

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

в ограниченной версии Linux (например, QNAP (nas), над которым я работал):
- связи не существовало!--6--> - 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

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

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

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

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


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

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

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


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


сочетание этих двух ответов (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, оставив в файле "matching_lines" результат.

вещи, которые нужно улучшить:

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

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

это должно помочь.