У меня есть массивный файл размером 80 ГБ, который мне нужно искать, используя строки в другом текстовом файле меньшего размера, и (вот кикер) мне нужно затем сохранить результаты для каждой подходящей строки в отдельные файлы, названные в строке поиска.
Какой самый эффективный способ справиться с этой задачей с помощью PHP или AWK?
Пример строки:
Оригинальный текстовый файл 80 ГБ:
line1 "value001","value002","Value003"line2 "Value004","Value005","Value006","Value007"line3 "value001","value002","Value003"line4 "value001","value002","Value003"line5 "value001","value002","Value003"line6 "Value004","Value005","Value006","Value007"line7 "value010","value022","Value009"
Поиск строки текстового файла search.txt
содержит эти значения:
Value003
Value007
Value009
Три текстовых файла будут содержать все соответствующие строки для каждой строки поиска:
Value003.txt would contain lines 1, 3, 4, 5
Value007.txt would contain lines 2 and 6
Value009.txt would contain line 7
Дополнительные разъяснения:
Если быть точным, строки представляют собой списки доменов и телефонных номеров, например:
joes.com
brick.net
moes.com
sams.net
2125551212
2025551212
(202)555-1212
В настоящее время я выполняю поиск с использованием длинной строки регулярного выражения в текстовой панели, например:
brick.net|joes.com|moes.com|sams.net|2125551212|2025551212|(202)555-1212
Этот поиск является одновременно громоздким, медленным и приводит к значительному количеству ложных срабатываний, таких как «сеть Самс» и «сеть из желтого кирпича».
Я пытаюсь зафиксировать выставленные значения, такие как [email protected], но не «сеть sams».
Цикл поиска в файле поиска и поиск по каждой строке, перенаправление результата в файл с правильным именем:
while read str; do grep -F "$str" infile > "$str".txt; done < search.txt
где infile
это ваш большой файл. Это приводит к следующим файлам:
==> Value003.txt <==
line1"value001","value002","Value003"line3"value001","value002","Value003"line4"value001","value002","Value003"line5"value001","value002","Value003"
==> Value007.txt <==
line2"Value004","Value005","Value006","Value007"line6"Value004","Value005","Value006","Value007"
==> Value009.txt <==
line7"value010","value022","Value009"
Обратите внимание, что это обрабатывает очень большой файл несколько раз, и, несмотря на то, что grep работает быстро, цикл по файлу с помощью Bash выполняется медленно, поэтому это возможно только в том случае, если search.txt
относительно небольшой.
Чтобы обработать большой файл только один раз, вы можете перебрать его с помощью awk, и для каждой строки проверить, совпадает ли какая-либо из строк:
#!/usr/bin/awk -f
# Read search file into array
NR == FNR {
searchstr[$0]
next
}
{
# Iterate over search strings
for (str in searchstr) {
# Print to file if matches
if (index($0, str)) {
print $0 > str ".txt"# next # Uncomment if only one search string can occur per line
# close(str ".txt") # Uncomment if there are too many open files
}
}
}
Это должно быть вызвано следующим образом:
awk -f script.awk search.txt infile
В менее читаемой однострочной версии:
awk 'NR==FNR{ss[$0];next}{for(s in ss)if(index($0,s))print$0>s".txt"}' search.txt infile
Обратите внимание, что у некоторых awk есть ограничение на количество открытых файловых дескрипторов.1, и другие (GNU awk) могут управлять большим количеством ресурсов, но замедлять его сверх этого предела — это зависит от размера вашего search.txt
, Если это станет проблемой, мы можем добавить close(str ".txt")
к if
пункт, чтобы закрыть файл после каждой записи.
Если в каждой строке может присутствовать только одна строка поиска, мы можем раскомментировать next
Заявление в цикле.
1 Оригинальный awk имел ограничение в 15 открытых файлов!
Если ваш ввод действительно такой, как показано, то все, что вам нужно с GNU awk, это:
NR==FNR{s=(s ? s "|" : "") $0; next} match($0,s,a){print > (a[0] ".txt")}
например.:
$ awk 'NR==FNR{s=(s ? s "|" : "") $0; next} match($0,s,a){print $0 "\t> " (a[0] ".txt")}' search.txt bigfile
line1"value001","value002","Value003" > Value003.txt
line2"Value004","Value005","Value006","Value007" > Value007.txt
line3"value001","value002","Value003" > Value003.txt
line4"value001","value002","Value003" > Value003.txt
line5"value001","value002","Value003" > Value003.txt
line6"Value004","Value005","Value006","Value007" > Value007.txt
line7"value010","value022","Value009" > Value009.txt
Если это не сработает, потому что ваши входные данные не совсем соответствуют показанным в вашем вопросе, тогда, очевидно, отредактируйте свой вопрос, чтобы показать более точный репрезентативный пример ввода и вывода.