2016-01-06 20 views
6

Mam plik1, który ma kilka linii (dziesiątek) i znacznie dłuższy plik2 (~ 500 000 linii). Wiersze w każdym pliku nie są identyczne, chociaż istnieje podzbiór identycznych pól. Chcę pobrać pola 3-5 z każdej linii w pliku1 i wyszukać plik2 dla tego samego wzorca (tylko te trzy pola, w tej samej kolejności - w pliku2, mieszczą się w polach 2-4). Jeśli znaleziono dopasowanie, to chcę usunąć odpowiednią linię z pliku1.awk/sed/grep, aby usunąć linie pasujące do pól w innym pliku

Np plik1:

2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T07:53:50 2016-01-06T07:52:14 2016006 090E A TM Current 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

plik2:

2016-01-06T07:35:06.87 2016003 100E C NN Current 0 
2016-01-06T07:35:09.97 2016003 100E B TM Current 6303 
2016-01-06T07:36:23.12 2016004 030N C TM Current 0 
2016-01-06T07:37:57.36 2016006 090E A TM Current 399 
2016-01-06T07:40:29.61 2016006 010N C TM Current 0 

... (i do 500.000 linii)

Więc w tym przypadku, chcę usunąć czwartej linii z pliku1 (na miejscu).

Poniższa znajdzie linie Chcę usunąć:

grep "$(awk '{print $3,$4,$5}' file1)" file2 

Więc jedno rozwiązanie może być do tego celu rury sed, ale jestem jasne, w jaki sposób ustawić wzorzec dopasowania w sed od wejścia rurami. Wyszukiwanie w Internecie sugeruje, że awk może to wszystko zrobić (a może sed, lub coś innego), zastanawiając się, jak mogłoby wyglądać czyste rozwiązanie.

Prędkość jest również ważna, ponieważ inne procesy mogą próbować modyfikować pliki podczas ich wykonywania (wiem, że może to spowodować więcej komplikacji ...). Dopasowania zwykle znajdują się na końcu pliku 2, a nie na początku (w przypadku, gdy istnieje sposób na wyszukiwanie pliku 2 od dołu do góry).

+0

pluse-uno na doskonale opisanym problemem. Kontynuuj wysyłkę i powodzenia. – shellter

Odpowiedz

4
$ awk 'NR==FNR{file2[$2,$3,$4]; next} !(($3,$4,$5) in file2)' file2 file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

Fakt, że plik2 zawiera 500.000 linii nie powinno być problemem dla pamięci awk wrt lub szybkości wykonania - należy ukończyć w około 1 sekundy lub mniej, nawet w najgorszym przypadku.

Przy każdym poleceniu UNIX, aby zastąpić oryginalny plik po prostu zrobić:

cmd file > tmp && mv tmp file 

więc w tym przypadku:

awk '...' file2 file1 > tmp && mv tmp file1 
+0

Dzięki. Rozumiem, jak to działa i jest dość szybkie. Próbowałem zrobić to na odwrót, odczytując plik1 do tablicy (ponieważ jest o wiele mniejszy), ale nie wiem, jak wydrukować linie z pliku1, które nie pasują do siebie. – trid3

+0

Więc teraz wiesz, że odczytywanie pliku1 do tablicy jest błędnym podejściem, prawda? Zrobiłoby to ci zaoszczędzić pamięć, ale wtedy musiałbyś przechodzić przez całą tablicę file1 raz dla każdego wiersza pliku 2, aby zwiększyć czas potrzebny skryptowi do działania przez współczynnik mnożenia liczby linii w plik1. –

+0

Np. Coś takiego: awk 'NR == FNR {plik1 [3 $, 4 $, 5 $]; następny}! ((2 $, 3 $, 4 $) w pliku1) {drukuj XX} 'plik1 plik2. Czym może być XX? Gdybyśmy mogli po prostu grep file1 dla (2 $, 3 $, 4 $) (teraz, gdy wiemy, że nie istnieje w pliku 2), i wydrukować to, to by się udało. – trid3

1

można znaleźć niedopasowane wiersze w file1:

$ grep -v -F -f <(awk '{ print $3,$4,$5 }' file2) file1 
2016-01-06T05:38:31 2016-01-06T05:23:33 2016006 120E A TM Current 
2016-01-06T07:34:01 2016-01-06T07:01:51 2016006 090E B TM Current 
2016-01-06T07:40:44 2016-01-06T07:40:41 2016006 080E A TM Alt 
2016-01-06T08:14:45 2016-01-06T08:06:33 2016006 080E C TM Current 

Wystarczy przekierować to gdzieś i nadpisać file1 później.

+0

Absolutnie NIE rób tak, ponieważ, mimo że może dać oczekiwane wyjście z tego przykładowego wejścia, generalnie otrzymasz fałszywe dopasowania w zależności od zawartości dwóch plików, ponieważ jest to gręplowanie dla zawartości pliku2 w całym każdym wierszu z pliku 1 zamiast w tylko polach docelowych pliku file1. –