Como fazer anti-join ou inverse join em bash

Quero realizar o que alguns softwares de análise de dados chamam de anti-join: remover de uma lista essas linhas linhas correspondentes em outra lista. Aqui estão alguns dados de brinquedo e a saída esperada:

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

Comentários

Resposta

Eu não usaria join para isso porque join exige que a entrada seja classificada, o que é uma complicação desnecessária para um trabalho tão simples. Você pode usar grep:

$ grep -vxFf list2 list1 a b 

Ou awk:

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

Se os arquivos já estiverem classificados, uma alternativa para join -v 1 seria comm -23

$ comm -23 list1 list2 a b 

Comentários

  • Evitar sort com grep é ótimo pelos dados de brinquedo que forneci. Obrigado! No mundo real, meu arquivo1 geralmente tem várias colunas de dados, uma das quais está sendo usada para a junção. Uma versão modificada de seu awk o código resolveria esse caso de uso.
  • @Josh sim, basta alterar o $0 com $N onde N é o número do campo no qual você está se juntando.
  • Isso funciona mesmo se os números das colunas em arquivo1 e arquivo2 forem diferentes: como awk ' NR == FNR {++ a [$ 2]}! a [$ 5] ' lista2 lista1; bastante comum para o arquivo de tag ter um formato diferente dos dados principais.

Resposta

Uma maneira de faça isso com o utilitário join:

$ join -v 1 list1 list2 a b 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *