it-swarm.com.ru

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

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

162
too much php

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

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

Вот:

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

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

194
Jonathan Leffler

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

57
Stephan Wehner

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

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

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

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

24
Johannes Schaub - litb

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

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

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

24
Tatjana Heuser

В то время как

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

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

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

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

18
ferdy
Perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/'  file1 file2
8
user2592005
awk 'NR==FNR{a[$1]++;next} a[$1] ' file1 file2
5
R S John

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

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

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

4
Basj

На ограниченной версии 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
3
Master DJon

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


Объединяя эти два ответа ( 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).
  • Может быть, добавить номер строки рядом с соответствующей строкой
2
akarpovsky