grep a large list against a large file
Obecnie próbuję grep
uzyskać dużą listę identyfikatorów (~5000) w stosunku do jeszcze większego pliku csv (3.000.000 linii).
Chcę wszystkie linie csv, które zawierają id z pliku id.
Moje naiwne podejście było:
cat the_ids.txt | while read line
do
cat huge.csv | grep $line >> output_file
done
Ale to trwa wieczność!
Czy istnieją bardziej efektywne podejścia do tego problemu?
3 answers
Spróbuj
grep -f the_ids.txt huge.csv
Dodatkowo, ponieważ twoje wzorce wydają się być stałymi ciągami, podanie opcji -F
może przyspieszyć 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.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-15 12:14:23
Użyj grep -f
do tego:
grep -f the_ids.txt huge.csv > output_file
From man grep
:
- f Plik, --file=Plik
Uzyskaj wzorce z pliku, po jednym na linię. Pusty plik zawiera zero wzory, a zatem nic nie pasuje. (- f jest określone przez POSIX.)
Jeśli podasz przykładowe dane wejściowe, może uda nam się nawet poprawić stan grep
trochę bardziej.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-15 12:13:35
grep -f filter.txt data.txt
staje się niesforny, gdy filter.txt
jest większy niż kilka tysięcy linii i dlatego nie jest najlepszym wyborem dla takiej sytuacji. Nawet podczas używania grep -f
, musimy pamiętać o kilku rzeczach:
- użyj opcji
-x
, jeśli istnieje potrzeba dopasowania całej linii w drugim pliku - użyj
-F
jeśli pierwszy plik ma ciągi znaków, a nie wzorce - użyj
-w
, aby zapobiec częściowemu dopasowaniu, nie używając opcji-x
This post has a great discussion w tym temacie ({[6] } na dużych plikach):
A ten post mówi o grep -vf
:
Podsumowując, najlepszym sposobem obsługi grep -f
na dużych plikach jest:
Dopasowanie całej linii:
awk 'FNR==NR {hash[$0]; next} $0 in hash' filter.txt data.txt > matching.txt
Dopasowanie określonego pola w drugim pliku (użycie ogranicznika ',' i pola 2 w ten przykład):
awk -F, 'FNR==NR {hash[$1]; next} $2 in hash' filter.txt data.txt > matching.txt
Oraz dla grep -vf
:
Dopasowanie całej linii:
awk 'FNR==NR {hash[$0]; next} !($0 in hash)' filter.txt data.txt > not_matching.txt
Dopasowanie określonego pola w drugim pliku (użycie ogranicznika ',' i pola 2 w tym przykładzie):
awk -F, 'FNR==NR {hash[$0]; next} !($2 in hash)' filter.txt data.txt > not_matching.txt
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 13:46:42