Как извлечь общие строки из нескольких файлов?

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

File1:

id1
id2
id3

file2:

id2
id3
id4

file3:
id10
id2
id3

file4

id100
id45
id3
id2

I need the output be like:

newfile:

id2 
id3

Я знаю, что эта команда работает для каждой пары файлов:

grep -w -f file1 file2> output

но мне нужна команда для работы более чем на 2 файла.

Любое предложение, пожалуйста?

4 ответа

Решение

Используя grep

Один и тот же трюк можно использовать более одного раза:

$ grep -w -f file1 file2 | grep -w -f file3 | grep -w -f file4
id2
id3

Кстати, если вы ищете точные совпадения, а не совпадения с регулярным выражением, лучше и быстрее использовать -F флаг:

$ grep -wFf file1 file2 | grep -wFf file3 | grep -wFf file4
id2
id3

Использование awk

$ awk 'FNR==1{nfiles++; delete fseen} !($0 in fseen){fseen[$0]++; seen[$0]++} END{for (key in seen) if (seen[key]==nfiles) print key}' file1 file2 file3 file4
id3
id2
  • FNR==1{nfiles++; delete fseen}

    Каждый раз, когда мы начинаем читать новый файл, мы делаем две вещи: (1) увеличиваем счетчик файлов, nfiles, и (2) удалить массив fseen,

  • !($0 in fseen){fseen[$0]; seen[$0]++}

    Если текущая строка не является ключом в fseenзатем добавьте его в fseen и увеличить счетчик для этой строки в seen,

  • END{for (key in seen) if (seen[key]==nfiles) print key}

    После того, как мы прочитали последнюю строку последнего файла, мы смотрим на каждый ключ в seen, Если количество для этого ключа равно числу файлов, которые мы прочитали, nfilesЗатем мы печатаем этот ключ.

Perl на помощь:

perl -lne 'BEGIN { $count = @ARGV }
           $h{$_}{$ARGV} = 1;
           }{
           print $_ for grep $count == keys %{ $h{$_} }, keys %h
           ' file* > newfile
  • -n читает входные файлы построчно
  • -l добавляет новую строку в print
  • @ARGV массив содержит имена входных файлов, присваивая его $count на BEGINНин просто считает их
  • $ARGV содержит имя текущего входного файла
  • $_ содержит текущую строку, прочитанную из файла.
  • %h хеш содержит идентификаторы в качестве ключей, каждый ключ содержит ссылку на хеш с именами файлов, которые содержат идентификатор в качестве ключей
  • }{ является оператором "эскимосского приветствия", он вводит код, который выполняется после исчерпания ввода
  • мы выводим только идентификаторы, количество файлов которых эквивалентно количеству всех файлов. Это работает для любого количества файлов.
     grep -hxf file1 file2 file3 file4 |sort -u
     id2
     id3

     # For storing it to any file, 
     grep -hxf file1 file2 file3 file4 |sort -u > output.txt

Команда zet обеспечивает набор операций между входными файлами. Использовать intersectвозможность получить общие строки во всех входных файлах. Входной контент не нужно сортировать. Порядок вывода будет таким же, как порядок входных строк.

      $ zet intersect file1 file2 file3 file4
id2
id3

Вот некоторые важные детали из раздела примечаний:

  • Каждая строка вывода встречается только один раз, потому что мы рассматриваем файлы как наборы, а строки как их элементы.
  • Zet считывает файлы целиком в память. Его использование памяти примерно пропорционально размеру файла его самого большого аргумента плюс размер (возможного) вывода.
Другие вопросы по тегам