Jeśli twoim celem jest znalezienie wspólnych lub nietypowych linii, comm
polecę tutaj.
Porównuje dwa pliki i pokazuje - w trzech kolumnach - linie, które są unikalne dla pliku 1, linie, które są unikalne dla pliku 2 oraz linie, które pojawiają się odpowiednio w obu plikach. Możesz przekazać flagi, aby ukryć dowolne z tych danych wyjściowych. Np. comm -1 file1 file2
Pominie pierwszą kolumnę, rzeczy unikalne dla file1. comm -12 file1 file2
pokaże tylko rzeczy w obu plikach.
Jest jedno duże zastrzeżenie: dane wejściowe muszą być posortowane. Możemy to obejść.
To pokaże ci wszystko w abc, którego nie ma w mno:
comm -23 <(sort abc.txt) <(sort mno.txt)
Możesz wc -l
to przeliczyć, żeby policzyć.
Powodem comm
jest to, że po posortowaniu plików porównanie obok siebie jest bardzo proste obliczeniowo. Jeśli masz do czynienia z milionami tych, to zrobi różnicę.
Można to wykazać za pomocą kilku próbnych plików. Mam dość szybki komputer, więc aby pokazać różnicę między podejściami, potrzebuję całkiem dużego zestawu próbek. Poszedłem do 10 milionów 10-znakowych ciągów na plik.
$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > abc.txt
$ cat /dev/urandom | tr -dc '0-9' | fold -w 10 | head -10000000 > mno.txt
$ time comm -23 <(sort abc.txt) <(sort mno.txt) | wc -l
... 0m10.653s
$ time grep -Fcxv -f abc.txt mno.txt
... 0m23.920s
$ time grep -Fcwv -f abc.txt mno.txt
... 0m40.313s
$ time awk 'NR==FNR{a[$0]++};NR!=FNR && a[$0]' abc.txt mno.txt | wc -l
... 0m12.161s
Sortowanie zajmuje mi większość czasu. Jeśli udajemy, że abc.txt jest statyczny, możemy go wstępnie posortować, co znacznie przyspieszy przyszłe porównania:
$ sort abc.txt abc-sorted.txt
$ time comm -23 abc-sorted.txt <(sort mno.txt) | wc -l
... 0m7.426s
Możesz na nie spojrzeć i uznać kilka sekund za nieistotne, ale muszę podkreślić, że działają one na wysokiej klasy komputerze. Jeśli chcesz to zrobić na (np.) Raspberry Pi 3, będziesz patrzył na znacznie wolniejsze zwroty, a różnica wzrośnie do punktu, w którym rzeczywiście ma znaczenie.
grep -cxvFf abc.txt mno.txt
?fgrep
,egrep
zastępcy są rzekomo przestarzałe (na korzyśćgrep -F
,grep -E
- chociaż nie jestem pewien, kto wierzy, że kiedykolwiek odejść-x
przy użyciu-F
?abcdef
powinien to liczyć jako dopasowanie, czy też brak dopasowania doabcd
?Przy pomocy awk możemy wykonać zadanie, przekazując dwa pliki, najpierw plik sygnatur, a następnie plik, który chcemy sprawdzić. Kiedy czytamy pierwszy plik, wiemy o tym
NR==FNR
i wtedy możemy wczytywać linie do tablicy. KiedyNR!=FNR
sprawdzamy, czy ustawiona jest tablica dla takiej linii.I odwrotnie, możemy zanegować wzór, aby wydrukować te linie, których nie ma
abc.txt
A jeśli chcemy wydrukować liczbę osób, które możemy zatrudnić
sort
iwc
:źródło
abc.txt
-mno.txt
która jest{xyz, pqrs}
.Jeśli jedna z list słów nie jest posortowana, szybsze byłoby użycie wydajnej struktury danych do zapamiętania typowych słów.
Pyton
Stosowanie:
Python (bardziej wydajny)
Jeśli chcesz zaoszczędzić trochę pamięci na pamięć pośrednią i czas działania, możesz użyć tego nieco trudniejszego do zrozumienia programu:
Wydajność
Biorąc pod uwagę,
abc.txt
orazmno.txt
z 1 mln nieposortowane linii 10 losowych znaków ASCII cyfr każda (patrz odpowiedź Oli za set-up):vs.
łącznie: 23 sekundy
źródło