Hur man gör anti-join eller inverse join i bash

Jag vill utföra vad en dataanalysprogramvara kallar anti-join: ta bort dessa rader från en lista matchande rader i en annan lista. Här är några leksaksdata och den förväntade utdata:

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

Kommentarer

  • Relaterar unix.stackexchange.com/q/11343/117549
  • Svarar det på din fråga? Finns det ett verktyg för att få raderna i en fil som inte finns i en annan?
  • @Muru, ja, det inlägget innehåller lösningarna presenteras i Terdons ' s svar. När jag letade efter " bash anti-join " (den terminologi jag associerar med den här typen av process) gjorde jag dock inte ' t hitta något användbart. Mitt OP (som andra har redigerat) uppgav att mitt uttryckliga syfte med att ställa denna fråga var att associera termen " anti-join " lösningarna, så att sökning av denna term ger dessa lösningar. Tack.

Svar

Jag skulle inte använda join för detta eftersom join kräver att ingångarna sorteras, vilket är en onödig komplikation för ett så enkelt jobb. Du kan istället använda grep:

$ grep -vxFf list2 list1 a b 

Eller awk:

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

Om filerna redan är sorterade skulle ett alternativ till join -v 1 vara comm -23

$ comm -23 list1 list2 a b 

Kommentarer

  • Att undvika sort med grep är bra för leksaksuppgifterna som jag tillhandahöll. Tack! I den verkliga världen har min fil1 ofta flera kolumner med data, varav en används för att gå med. En modifierad version av din awk kod skulle ta itu med detta användningsfall.
  • @Josh ja, ändra bara $0 med $N där N är fältnumret du går med på.
  • Detta fungerar även om kolumnnumren i fil1 och fil2 är olika: som awk ' NR == FNR {++ a [$ 2]}! a [$ 5] ' list2 list1; ganska vanligt att taggfilen har ett annat format än huvuddata.

Svar

Ett sätt att gör detta med join verktyget är:

$ join -v 1 list1 list2 a b 

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *