Cum se face unirea anti-join sau inversă în bash

Vreau să realizez ceea ce unele software-uri de analiză a datelor numesc anti-join: eliminați dintr-o listă acele linii potrivirea liniilor într-o altă listă. Iată câteva date despre jucării și rezultatul așteptat:

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

Comentarii

Răspuns

Nu aș folosi join pentru aceasta, deoarece join necesită sortarea intrărilor, ceea ce reprezintă o complicație inutilă pentru o lucrare atât de simplă. În schimb, puteți utiliza grep:

$ grep -vxFf list2 list1 a b 

Sau awk:

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

Dacă fișierele sunt deja sortate, o alternativă la join -v 1 ar fi comm -23

$ comm -23 list1 list2 a b 

Comentarii

  • Evitarea sort cu grep este grozavă pentru datele despre jucării pe care le-am furnizat. Mulțumesc! În lumea reală, fișierul meu1 are adesea mai multe coloane de date, dintre care una este utilizată pentru îmbinare. O versiune modificată a awk codul ar aborda acest caz de utilizare.
  • @Josh da, trebuie doar să schimbi $0 cu $N unde N este numărul câmpului la care vă alăturați.
  • Acest lucru funcționează chiar dacă numerele coloanelor din fișierul1 și fișierul2 sunt diferite: cum ar fi awk ' NR == FNR {++ a [$ 2]}! a [$ 5] ' list2 list1; destul de obișnuit ca fișierul de etichete să aibă un format diferit față de datele principale.

Răspuns

O modalitate de a faceți acest lucru cu utilitarul join este:

$ join -v 1 list1 list2 a b 

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *