Narzędzie w Uniksie do odejmowania plików tekstowych?

16

Mam duży plik złożony z pól tekstowych oddzielonych średnikami w postaci dużej tabeli. Zostało posortowane. Mam mniejszy plik złożony z tych samych pól tekstowych. W pewnym momencie ktoś połączył ten plik z innymi, a następnie zrobił coś w celu utworzenia dużego pliku opisanego powyżej. Chciałbym odjąć wiersze małego pliku od dużego (tj. Dla każdej linii w małym pliku, jeśli w dużym pliku istnieje pasujący ciąg, usuń tę linię w dużym pliku).

Plik wygląda mniej więcej tak

GenericClass1; 1; 2; NA; 3; 4;
GenericClass1; 5; 6; NA; 7; 8;
GenericClass2; 1; 5; NA; 3; 8;
GenericClass2; 2; 6; NA; 4; 1;

itp

Czy jest na to szybki, elegancki sposób, czy muszę użyć awk?

Escher
źródło

Odpowiedzi:

28

Możesz użyć grep. Daj mu mały plik jako dane wejściowe i powiedz mu, aby znalazł niepasujące linie:

grep -vxFf file.txt bigfile.txt > newbigfile.txt

Dostępne opcje to:

   -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.)
   -f FILE, --file=FILE
          Obtain  patterns  from  FILE,  one  per  line.   The  empty file
          contains zero patterns, and therefore matches nothing.   (-f  is
          specified by POSIX.)

   -v, --invert-match
          Invert the sense of matching, to select non-matching lines.  (-v
          is specified by POSIX.)
   -x, --line-regexp
          Select only those matches that exactly match the whole line.  
          (-x is specified by POSIX.)
terdon
źródło
Miło, działało idealnie. Dziękuję bardzo.
Escher
1
Fajnie, że zadziałało, ale wydaje mi się, że byłoby lepiej również z tą -xopcją, na wypadek gdyby linia w mniejszym pliku spotkała się z podciągiem innej linii w głównym pliku. Jest też całkiem możliwe, że odpowiedź @ UlrichSchwarz jest szybsza.
rici
18

comm jest twoim przyjacielem:

NAME comm - porównaj dwa posortowane pliki linia po linii

SKŁADNIA comm [OPCJA] ... PLIK1 PLIK2

OPIS Porównaj posortowane pliki PLIK1 i PLIK2 linia po linii.

   With  no  options, produce three-column output.  Column one contains lines unique to FILE1, column two contains
   lines unique to FILE2, and column three contains lines common to both files.

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

( commprawdopodobnie będzie miał przewagę nad wydajnością, grepponieważ bierze pod uwagę sortowanie).

Na przykład:

comm -1 -3 file.txt bigfile.txt > newbigfile.txt
Ulrich Schwarz
źródło
2
Dobra uwaga na temat używania comm przez grep do sortowania list. To byłaby lepsza odpowiedź, gdybyś podał konkretny przykład z linii poleceń, taki jakcomm -1 -3 file.txt bigfile.txt > newbigfile.txt
Steve Midgley
Potwierdzam, że próbowałem zgłosić powyższe polecenie grep z plikami około 100 MB i otrzymałem błąd „zabity”. Próbowanie z komunikatem zakończyło się pomyślnie.
Gianluca Casati
Przekierowanie polecenia jest przydatne w przypadku nieposortowanych plików lub jeśli potrzebujesz więcej niż dwóch plików:comm -1 -3 <(sort BAD.txt GOOD.txt) <(sort FILES.txt)
odinho - Velmont