Tubo de Diferença Simétrica?

3

Eu tenho um comando que produz listas de strings seguidas por novas linhas, a e um arquivo contendo uma lista de strings seguidas por novas linhas, b.txt . Preciso de um comando que calcule a diferença simétrica da saída de a e o conteúdo de b.txt . Idealmente, este comando deve operar em um pipeline, pois a é potencialmente muito lento.

Diagrama de Venn, se você gostar deles (Créditos para a Wikipédia):

Para aqueles mais orientados a exemplos:

a de saídas

apple
car

b.txt

banana
car
dog

Em seguida, o resultado deve ser

apple
banana
dog
    
por Nathan Ringo 01.01.2016 / 08:09

3 respostas

2

Sua solução de classificação pode ser um pouco mais rápida se você classificar os arquivos separadamente e, em seguida, use comm para encontrar as linhas não comuns:

sort a.txt -o a.txt
sort b.txt -o b.txt
comm -3 a.txt b.txt | sed 's/^\t//'

Como alternativa, se um dos seus arquivos de dados não for muito grande, você poderá ler tudo em um array associativo e comparar o outro arquivo linha por linha. Por exemplo, com o awk:

awk '
ARGIND==1 { item[$0] = 1; next }
ARGIND==2 { if(!item[$0])print; else item[$0] = 2 }
END   { for(i in item)if(item[i]==1)print i }
' a.txt b.txt

No acima, ARGIND conta os argumentos dos arquivos. A primeira linha salva o arquivo 1 linhas na matriz item . A próxima linha vê se a linha atual do arquivo 2 está nessa matriz. Se não for impresso, notamos que este item foi visto em ambos os arquivos. Finalmente, imprimimos os itens que não foram vistos nos dois arquivos.

Se um de seus arquivos for muito menor que o outro, é melhor colocá-lo primeiro nos argumentos para que a matriz de itens permaneça pequena:

if [ $(wc -l <a.txt) -lt $(wc -l <b.txt) ]
then args="a.txt b.txt"
else args="b.txt a.txt"
fi
awk '
ARGIND==1 { item[$0] = 1; next }
ARGIND==2 { if(!item[$0])print; else item[$0] = 2 }
END   { for(i in item)if(item[i]==1)print i }
' $args
    
por 01.01.2016 / 09:09
4

Você pode usar substituição de processo para tratar a saída de um comando como um arquivo.

comm -3 <(a | sort) <(sort b.txt)
    
por 01.01.2016 / 12:57
1

Uma boa ferramenta para ver as diferenças é diff , você só precisa jogar um pouco com suas opções não triviais para formatar a saída corretamente:

diff --unchanged-group-format= --new-group-format="%>" a b.txt

Se a não for um arquivo por pipe, você deverá usar - :

echo 'apple
car' | diff --unchanged-group-format= --new-group-format='%>' - b.txt

Saída:

apple
banana
dog

Ou se você não se importa com o contexto em que uma linha apareceu no arquivo:

echo 'apple
car' | sort | diff --unchanged-group-format= --new-group-format='%>' - <(sort b.txt)
    
por 01.01.2016 / 10:48