Slik gjør du anti-join eller inverse join in bash

Jeg vil utføre det noen dataanalyseprogramvare kaller anti-join: fjern disse linjene fra en liste samsvarende linjer i en annen liste. Her er noen leketøydata og forventet utdata:

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

Kommentarer

  • Relatert unix.stackexchange.com/q/11343/117549
  • Svarer dette på spørsmålet ditt? Er det et verktøy for å få linjene i en fil som ikke er i en annen?
  • @Muru, ja, det innlegget gir løsningene presentert i Terdon ' s svar. Da jeg imidlertid lette etter " bash anti-join " (terminologien jeg forbinder med denne typen prosesser), gjorde jeg ikke ' t finner noe nyttig. Min OP (som andre har redigert) uttalte at mitt eksplisitte formål med å stille dette spørsmålet var å knytte begrepet " anti-join " til løsningene, slik at søking i dette begrepet gir disse løsningene. Takk.

Svar

Jeg vil ikke bruke join for dette fordi join krever at input blir sortert, noe som er en unødvendig komplikasjon for en så enkel jobb. Du kan i stedet bruke grep:

$ grep -vxFf list2 list1 a b 

Eller awk:

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

Hvis filene allerede er sortert, ville et alternativ til join -v 1 være comm -23

$ comm -23 list1 list2 a b 

Kommentarer

  • Å unngå sort med grep er flott for leketøydataene jeg har oppgitt. Takk! I den virkelige verden har filen1 ofte flere kolonner med data, hvorav den ene brukes til sammenføyningen. En modifisert versjon av awk koden vil adressere denne brukssaken.
  • @Josh ja, bare endre $0 med $N der N er feltnummeret du blir med på.
  • Dette fungerer selv om kolonnetallene i file1 og file2 er forskjellige: som awk ' NR == FNR {++ a [$ 2]}! a [$ 5] ' list2 liste1; ganske vanlig for at tagfilen skal være et annet format enn hoveddataene.

Svar

En måte å gjør dette med join verktøyet er:

$ join -v 1 list1 list2 a b 

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *