Найти общие строки для нескольких файлов - PullRequest
3 голосов
/ 13 февраля 2020

У меня есть почти 200 файлов, и я хочу найти строки, общие для всех 200 файлов, строки выглядят так:

HISEQ1:105:C0A57ACXX:2:1101:10000:105587/1
HISEQ1:105:C0A57ACXX:2:1101:10000:105587/2
HISEQ1:105:C0A57ACXX:2:1101:10000:121322/1
HISEQ1:105:C0A57ACXX:2:1101:10000:121322/2
HISEQ1:105:C0A57ACXX:2:1101:10000:12798/1
HISEQ1:105:C0A57ACXX:2:1101:10000:12798/2

Есть ли способ сделать это пакетным способом?

Ответы [ 4 ]

6 голосов
/ 13 февраля 2020

Я не думаю, что есть команда unix, которую вы могли бы просто использовать для этой задачи. Но вы можете создать небольшой сценарий оболочки для команд comm и grep, как показано в следующем примере:

#!/bin/bash    

# Prepare 200 (small) test files
rm data-*.txt
for i in {1..200} ; do
    echo "${i}" >> "data-${i}.txt"
    # common line
    echo "foo common line" >> "data-${i}.txt"
done

# Get the common lines between file1 and file2.
# file1 and file2 can be random files out of the set,
# ideally they are the smallest ones
comm -12 data-1.txt data-2.txt > common_lines

# Now grep through the remaining files for those lines
for file in data-{3..100}.txt ; do
    # For each remaining file reduce the common_lines to those
    # which are found in that file
    grep -Fxf common_lines "${file}" > tmp_common_lines \
        && mv tmp_common_lines > common_lines
done

# Print the common lines
cat common_lines

Тот же подход можно использовать для больших файлов. Это займет больше времени, но потребление памяти останется линейным.

4 голосов
/ 13 февраля 2020

Не могли бы вы попробовать следующее. Справедливое предупреждение, это будет занимать память, так как данные хранятся в массиве.

awk '
FNR==1{
  file++
}
{
  a[$0]++
}
END{
 for(i in a){
   if(a[i]==file){
     print "Line " i " is found in all "file " files."
   }
 }
}' file1 file2 ....file200
3 голосов
/ 13 февраля 2020
awk '(NR==FNR){a[$0]=1;next}
     (FNR==1){ for(i in a) if(a[i]) {a[i]=0} else {delete a[i]} }
     ($0 in a) { a[$0]=1 }
     END{for (i in a) if (a[i]) print i}' file1 file2 file3 ... file200

Этот метод обрабатывает каждый файл построчно. Идея состоит в том, чтобы отслеживать, какие строки были замечены в текущем файле, используя ассоциативный массив a[line]. 1 означает, что строка видна в текущем файле, 0 означает, что строка не видна.

  1. (NR==FNR){a[$0]=1;next} сохранить первый файл в массив, проиндексированный строкой и отметьте его как видимый. (NR==FNR) - это условие, используемое для проверки первой строки.
  2. (FNR==1){for(i in a) if(a[i]) {a[i]=0} else {delete a[i]} }: если мы прочитаем первую строку файла, проверьте, какие строки были замечены в предыдущем файле. Если строка в массиве не видна, удалите ее, если она видна, сбросьте ее на невидимый (0). Таким образом, мы очищаем память и обрабатываем дубликаты строк в одном файле.
  3. ($0 in a) { a[$0]=1 }: на строку, проверяем, является ли строка членом массива, если она пометьте его как видимое (1)
  4. END{for (i in a) if(a[i]) print i}: после обработки всех строк проверьте, какие строки печатать.
0 голосов
/ 13 февраля 2020

Мой подход заключается в создании суперфайла, в начале которого есть столбец для имени файла и номера строки, затем соответствующая строка содержимого, сортируйте этот файл по столбцу содержимого.

Grep может генерировать первая часть этого, особенно если вы можете исключить некоторую часть файла

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...