Używam Solaris 10, więc opcje grep obejmujące -f nie działają.
Mam dwa pliki oddzielone potokami:
plik1:
abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|
plik 2:
abc|123|
kumar|pki|
cab|234
Chciałbym porównać dwie pierwsze kolumny pliku 2 z plikiem 1 (przeszukaj całą zawartość pliku 1 w pierwszych dwóch kolumnach), jeśli pasują, wydrukuj dopasowaną linię pliku 1. Następnie wyszukaj drugą linię pliku 2 i tak dalej.
Oczekiwany wynik:
abc|123|BNY|apple|
cab|234|cyx|orange|
Pliki, które mam, są ogromne i zawierają około 400 000 wierszy, dlatego chciałbym, aby wykonanie było szybkie.
shell-script
text-processing
perl
użytkownik68365
źródło
źródło
grep
, jest poniżej/usr/sfw/bin/ggrep
. stackoverflow.com/questions/15259882/…Odpowiedzi:
Właśnie do tego przeznaczony jest awk:
Wyjaśnienie
-F'|'
: ustawia separator pól na|
.NR==FNR
: NR jest bieżącym numerem linii wejściowej, a FNR numerem bieżącego pliku. Oba będą równe tylko podczas odczytywania pierwszego pliku.c[$1$2]++; next
: jeśli jest to pierwszy plik, zapisz pierwsze dwa pola wc
tablicy. Następnie przejdź do następnego wiersza, aby zastosować go tylko do pierwszego pliku.c[$1$2]>0
: blok else zostanie wykonany tylko wtedy, gdy jest to drugi plik, więc sprawdzamy, czy pola 1 i 2 tego pliku były już widoczne (c[$1$2]>0
), a jeśli tak, to wypisujemy wiersz. Wawk
domyślnym działaniem jest drukowanie linii, więc jeślic[$1$2]>0
jest prawdziwa, linia zostanie wydrukowany.Alternatywnie, ponieważ otagowałeś Perl:
Wyjaśnienie
Pierwszy wiersz się otworzy
file2
, przeczyta wszystko do drugiego|
(.+?\|[^|]+
) i zapisze to ($&
jest wynikiem operatora ostatniego dopasowania) w%k
haszu.Druga linia przetwarza plik 1, używa tego samego wyrażenia regularnego do wyodrębnienia dwóch pierwszych kolumn i wydrukowania linii, jeśli kolumny te są zdefiniowane w
%k
haszowaniu.Oba powyższe podejścia będą musiały przechowywać 2 pierwsze kolumny pliku2 w pamięci. Nie powinno to stanowić problemu, jeśli masz tylko kilkaset tysięcy linii, ale jeśli tak, możesz zrobić coś takiego
Ale to będzie wolniejsze.
źródło
file2
do pamięci?awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0'
jest krótszą wersją.file2
mają zduplikowane wiersze?Myślę
jest tym, czego szukasz. Powinien być wydajny, ale nie jestem pewien, czy będzie tak dokładny, jak chcesz. Jeśli
abc|123
(na przykład) zostanie znaleziony w wierszufile1
w różnych kolumnach, wiersz ten zostanie również wydrukowany. Jeśli możesz zagwarantować, że tak się nigdy nie stanie, powyższa linia powinna działać.źródło
Jeśli chcesz myśleć o problemie w sposób podobny do SQL, zdecydowanie powinieneś wypróbować narzędzie o nazwie „ q ”:
Jest to bardziej jasne i łatwiejsze do zrozumienia, jeśli znasz kwerendę SQL.
źródło
źródło