Grep большой список против большого файла
В настоящее время я пытаюсь grep
добавить большой список идентификаторов (~ 5000) к еще большему файлу csv (3.000.000 строк).
Я хочу, чтобы все строки csv содержали идентификатор из файла id.
Мой наивный подход:
cat the_ids.txt | while read line
do
cat huge.csv | grep $line >> output_file
done
Но это берет навсегда!
Существуют ли более эффективные подходы к этой проблеме?
Ответы
Ответ 1
Try
grep -f the_ids.txt huge.csv
Кроме того, поскольку ваши шаблоны кажутся фиксированными строками, поставка опции -F
может ускорить grep
.
-F, --fixed-strings
Interpret PATTERN as a list of fixed strings, separated by
newlines, any of which is to be matched. (-F is specified by
POSIX.)
Ответ 2
Используйте grep -f
для этого:
grep -f the_ids.txt huge.csv > output_file
От man grep
:
-f FILE, --file = FILE
Получить шаблоны из FILE, по одному на строку. Пустой файл содержит нуль шаблонов и, следовательно, ничего не соответствует. (-f указан POSIX.)
Если вы предоставите некоторый ввод проб, возможно, мы даже немного улучшим условие grep
.
Test
$ cat ids
11
23
55
$ cat huge.csv
hello this is 11 but
nothing else here
and here 23
bye
$ grep -f ids huge.csv
hello this is 11 but
and here 23
Ответ 3
grep -f
становится неуправляемым с большими файлами. Даже при использовании grep -f
нам нужно помнить несколько вещей:
- используйте опцию
-x
, если необходимо совместить всю строку во втором файле
- используйте
-F
, если в первом файле есть строки, а не шаблоны
- используйте
-w
для предотвращения частичных совпадений, не используя опцию -x
У этого сообщения есть отличная дискуссия по этой теме (grep -f
на больших файлах):
И этот пост говорит о grep -vf
:
Таким образом, лучший способ обработки grep -f
для больших файлов:
Соответствие всей строки:
awk 'FNR==NR {hash[$0]; next} $0 in hash' filter.txt data.txt > matching.txt
Согласование определенного поля во втором файле (с использованием разделителя "," и поля 2 в этом примере):
awk -F, 'FNR==NR {hash[$1]; next} $2 in hash' filter.txt data.txt > matching.txt
и для grep -vf
:
Соответствие всей строки:
awk 'FNR==NR {hash[$0]; next} !($0 in hash)' filter.txt data.txt > not_matching.txt
Согласование определенного поля во втором файле (с использованием разделителя "," и поля 2 в этом примере):
awk -F, 'FNR==NR {hash[$0]; next} !($2 in hash)' filter.txt data.txt > not_matching.txt