Jak wykonać anty-łączenie lub sprzężenie odwrotne w bash

Chcę wykonać to, co niektóre programy do analizy danych nazywają anty-złączeniem: usuń z jednej listy te linie pasujące wiersze na innej liście. Oto niektóre dane dotyczące zabawki i oczekiwane wyniki:

$ echo -e "a\nb\nc\nd" > list1 $ echo -e "c\nd\ne\nf" > list2 $ antijoincommand list1 list2 a b 

Komentarze

Odpowiedź

Nie użyłbym join dlatego, że join wymaga posortowania danych wejściowych, co jest niepotrzebną komplikacją w przypadku tak prostej pracy. Zamiast tego można użyć grep:

$ grep -vxFf list2 list1 a b 

Lub awk:

$ awk "NR==FNR{++a[$0]} !a[$0]" list2 list1 a b 

Jeśli pliki są już posortowane, alternatywą dla join -v 1 byłoby comm -23

$ comm -23 list1 list2 a b 

Komentarze

  • Unikanie sort z grep jest świetne za dostarczone przeze mnie dane zabawki. Dzięki! W prawdziwym świecie mój plik1 często zawiera wiele kolumn danych, z których jedna jest używana do łączenia. Zmodyfikowana wersja Twojego awk kod rozwiązałby ten przypadek użycia.
  • @Josh tak, po prostu zmień $0 na $N gdzie N to numer pola, do którego się przyłączasz.
  • Działa to nawet wtedy, gdy numery kolumn w pliku1 i pliku2 są różne, np. awk ' NR == FNR {++ a [$ 2]}! a [$ 5] ' list2 list1; dość typowe dla pliku znaczników jest inny format niż główne dane.

Odpowiedź

Jeden sposób zrób to za pomocą narzędzia join:

$ join -v 1 list1 list2 a b 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *