Sådan gør du anti-join eller invers join i bash

Jeg vil udføre, hvad nogle dataanalysesoftware kalder en anti-join: fjern disse linjer fra en liste matchende linjer i en anden liste. Her er nogle legetøjsdata og den forventede output:

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

Kommentarer

  • Forhold unix.stackexchange.com/q/11343/117549
  • Besvarer dette dit spørgsmål? Er der et værktøj til at få linjerne i en fil, der ikke er i en anden?
  • @Muru, ja, det indlæg giver løsningerne præsenteret i Terdon ' s svar. Da jeg søgte efter " bash anti-join " (den terminologi, jeg forbinder med denne form for proces), gjorde jeg ikke ' t finde noget nyttigt. Min OP (som andre har redigeret) sagde, at mit eksplicitte formål med at stille dette spørgsmål var at knytte udtrykket " anti-join " til løsningerne, så at søge i dette udtryk giver disse løsninger. Tak.

Svar

Jeg vil ikke bruge join til dette fordi join kræver, at input sorteres, hvilket er en unødvendig komplikation for et så simpelt job. Du kan i stedet bruge grep:

$ grep -vxFf list2 list1 a b 

Eller awk:

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

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

$ comm -23 list1 list2 a b 

Kommentarer

  • Undgå sort med grep er fantastisk til de legetøjsdata, jeg leverede. Tak! I den virkelige verden har min fil1 ofte flere kolonner med data, hvoraf den ene bruges til sammenføjningen. En ændret version af din awk kode vil adressere denne brugssag.
  • @Josh ja, skift bare $0 med $N N er feltnummeret, du deltager i.
  • Dette fungerer, selvom kolonnetalene i fil1 og fil2 er forskellige: som awk ' NR == FNR {++ a [$ 2]}! a [$ 5] ' list2 liste1; ganske almindeligt, at tagfilen skal være et andet format end hoveddataene.

Svar

En måde at gør dette med join hjælpeprogrammet er:

$ join -v 1 list1 list2 a b 

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *