Каков наилучший способ сравнить 2 больших файла на основе первого токена в каждой строке? - PullRequest
0 голосов
/ 25 марта 2019

У меня есть 2 больших файла (каждый около 500 тыс. Строк или 85 МБ), содержащих контрольную сумму файла и сам путь к файлу. Каков наилучший способ получить различия между файлами на основе контрольной суммы? Я могу написать программу на Java, скрипт и т. Д., Но цель в том, чтобы она была эффективной.

Например, у меня есть Файл A:

ec7a063d3990cf7d8481952ffb45f1d8b490b1b5  /home/user/first.txt
e0f886f2124804b87a81defdc38ad2b492458f34  /home/user/second.txt

Файл B:

650bc1eb1b24604819eb342f2ebc1bab464d9210  /home/user/third.txt
ec7a063d3990cf7d8481952ffb45f1d8b490b1b5  /home/user/blah/dup.txt

Я хочу вывести два файла, содержащие уникальные файлы в файлах A и B.

UniqueA

e0f886f2124804b87a81defdc38ad2b492458f34  /home/user/second.txt

UniqueB

650bc1eb1b24604819eb342f2ebc1bab464d9210  /home/user/third.txt

В этом случае «first.txt» и «dup.txt» совпадают, поскольку их контрольная сумма одинакова, поэтому я исключаю ее как не уникальную. Какой самый эффективный способ сделать это? Файлы никак не сортируются.

Ответы [ 3 ]

1 голос
/ 25 марта 2019

Итак, вот быстрый ответ, но он не так эффективен:

$ join -v1 <(sort FileA) <(sort FileB) | tee UniqueA
e0f886f2124804b87a81defdc38ad2b492458f34 /home/user/second.txt

$ join -v2 <(sort FileA) <(sort FileB) | tee UniqueB
650bc1eb1b24604819eb342f2ebc1bab464d9210 /home/user/third.txt

Команда join сопоставляет строки из двух отсортированных файлов по ключу (который по умолчанию является первым полем с разделителем пробелов по умолчанию). Однако приведенные выше команды не так эффективны, потому что мы сортируем файлы дважды: один раз, чтобы получить значения, уникальные для первого файла (-v1), а затем снова, чтобы получить уникальные значения из второго (-v2). В скором времени я опубликую некоторые улучшения.

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

$ join -v1 -v2 <(sort FileA) <(sort FileB)
650bc1eb1b24604819eb342f2ebc1bab464d9210 /home/user/third.txt
e0f886f2124804b87a81defdc38ad2b492458f34 /home/user/second.txt

На данный момент у нас почти есть наш ответ. У нас есть все непревзойденные файлы из обоих файлов. Более того, мы отсортировали каждый файл только один раз. Я считаю, что это эффективно. Однако вы потеряли информацию о происхождении. Мы можем пометить строки с помощью sed, используя эту итерацию или код:

$ join -v1 -v2 <(sort FileA | sed s/$/\ A/ ) <(sort FileB | sed s/$/\ B/ )
650bc1eb1b24604819eb342f2ebc1bab464d9210 /home/user/third.txt B
e0f886f2124804b87a81defdc38ad2b492458f34 /home/user/second.txt A

На данный момент у нас есть уникальные записи, и мы знаем файл, из которого они пришли. Если вы должны иметь результаты в отдельных файлах, я думаю, что вы можете сделать это с помощью awk (или просто с помощью bash). Вот еще одна итерация кода с включенным awk:

join -v1 -v2 <(sort FileA | sed s/$/\ A/ ) <(sort FileB | sed s/$/\ B/ ) |  awk '{ file="Unique" $3 ; print $1,$2 > file }
0 голосов
/ 25 марта 2019

решение только для bash:

# create a file with a mark that help to find the source of the hash remove duplicate 
sed 's/^\([0-9a-f]*\)[^0-9a-f]/\1=A=/' FileA | sort | uniq -w 32 > FileA.mark
sed 's/^\([0-9a-f]*\)[^0-9a-f]/\1=B=/' FileB | sort | uniq -w 32 > FileB.mark

# sort the 2 files together , keep only unique hashs 
sort -t= FileA.mark FileB.mark | uniq -w 32 -c  >  HashCountFromAB

# if the count equal 1 ( provide by option -c from uniq )
# we use the mark to find the origin of the hash 

grep '^ *1 [0-9a-f]*=A=' HashCountFromAB > FileA.uniq
grep '^ *1 [0-9a-f]*=B=' HashCountFromAB > FileB.uniq
0 голосов
/ 25 марта 2019

Сортируйте каждый файл с sort, затем сравните результаты с comm.Использование обеих команд объяснено на страницах справочника по имени.

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