Обработка больших данных: удаление строк в одном текстовом документе, найденном в другом

339
AndrewWilliams

У меня есть 2 больших текстовых файла (~ 500M, ~ 15GB ea), которые выглядят так:

FileP.txt:

test@test.com: testtest test@test.com1: testtest1 test@test.com2: testtest2 test@test.com3: testtest3 test@test.com4: testtest4

FileE.txt

test@test.com:testtest test@test.com0:testtest0 test@test.com2:testtest2 test@test.com3:testtest3 test@test.com5:testtest5 

(Обратите внимание, что в нем FileE.txtесть строки, которых нет FileP.txt. Я не хочу, чтобы они были включены. Жирные линии - это строки, которые должны заканчиваться output.txt, поскольку их нет FileE.txt.)

Я хочу, чтобы запустить FileE.txtпротив FileP.txtи удалить все строки, которые были найдены в FileE.txtот FileP.txtи выхода в новый файл.

Это должно выглядеть так:

output.txt:

test@test.com1: testtest1 test@test.com4: testtest4

Я попробовал несколько команд,

Вот моя команда grep:

$ grep -Fvxf FileE.txt FileP.txt > output.txt 

Тем не менее, я получаю эту ошибку (очевидно, потому что файлы слишком велики):

grep: memory exhausted 

Для тех, кто заинтересован, работает $ ulimit -aвозврат:

core file size (blocks, -c) unlimited data seg size (kbytes, -d) unlimited file size (blocks, -f) unlimited open files (-n) 256 pipe size (512 bytes, -p) 8 stack size (kbytes, -s) 2032 cpu time (seconds, -t) unlimited max user processes (-u) 256 virtual memory (kbytes, -v) unlimited 

Итак, мой вопрос, что было бы наиболее эффективным и простым способом завершить этот процесс?

ПРИМЕЧАНИЕ. Файлы не отсортированы.

1
Файлы гарантированно будут отсортированы? Пожалуйста, не отвечайте в комментариях; [отредактируйте] ваш вопрос, чтобы сделать его более понятным и полным. Scott 5 лет назад 0
Сортируйте файлы, выполните `diff FileP.txt File.txt` и оставьте только строки с префиксом` <`? xenoid 5 лет назад 1
@ Скотт Готово. Как бы сохранить строки только с префиксом AndrewWilliams 5 лет назад 0
Еще одна идея? Получить их в базу данных MySQL. С такими большими данными, простой текстовый файл никогда не будет отличным вариантом. Даже если эта база данных MySQL считается только огромным кешем. Тем не менее, если вам нужно остаться в мире командной строки, я чувствую вашу боль. JakeGould 5 лет назад 0
@ JakeGould Я думал об этом, честно. Я должен остаться в CL :( AndrewWilliams 5 лет назад 0

2 ответа на вопрос

0
Scott

Если файлы отсортированы, сделайте

comm -23 fileP.txt fileE.txt 

commсравнивает два отсортированных файла и ищет общие для них строки. Например, учитывая этот файл цветов, имена которых начинаются с согласных:

blue green purple red white yellow 

и этот список цветов, имена которых заканчиваются на гласные:

blue indigo orange purple white 

команда comm colors1 colors2выдает такой вывод:

 blue green indigo orange purple red white yellow 

где:
первый столбец содержит цвета, которые начинаются и заканчиваются согласными (в, colors1но не colors2), второй столбец содержит цвета, начинающиеся и заканчивающиеся гласными (в, colors2но не colors1), а третий столбец содержит цвета, которые начинаются с согласных и заканчиваются гласными (в обоих colors1и colors2). Для ваших файлов (показано в вашем вопросе), comm fileP.txt fileE.txtпроизводит

 test@test.com:testtest test@test.com0:testtest0 test@test.com1:testtest1 test@test.com2:testtest2 test@test.com3:testtest3 test@test.com4:testtest4 test@test.com5:testtest5 

Варианты немного не интуитивно понятны: -23средства подавляют второй и третий столбцы, показывая только первый (строки, которые находятся в первом файле, но не во втором). Так,

$ comm -23 fileP.txt fileE.txt test@test.com1:testtest1 test@test.com4:testtest4 

Обратите внимание, что это не будет работать правильно, если файлы не отсортированы. Если файлы не отсортированы, сортируйте их.

0
Scott

Чтобы увеличить комментарий по xenoid, отсортируйте файлы и введите

diff fileP.txt fileE.txt | sed -n 's/^< //p' 

Выходные данные diffпоказывают строки, которые находятся только в первом файле, с предшествующим , и строки, которые находятся только во втором файле, с предшествующим . В sedвыбирает только те строки, которые начинаются с и полосы его.

Похожие вопросы