Linux / Comando comm: comparar linhas comuns e exclusivas

comm compara dois arquivos de texto previamente ordenados e mostra três categorias: linhas apenas no primeiro, apenas no segundo e comuns aos dois. As opções -1, -2 e -3 ocultam as colunas correspondentes; por exemplo, -12 deixa somente as linhas comuns.

A comparação é feita por linhas inteiras na ordem de classificação. Para examinar alterações e sua posição no texto, use o comando diff. Antes de tratar os resultados de comm como comparação de conjuntos, decida se repetições do mesmo valor devem ser preservadas ou removidas.

Sintaxe e ordenação das entradas

comm [opção...] arquivo1-ordenado arquivo2-ordenado

Essa é uma descrição da sintaxe; substitua os marcadores pelos nomes desejados. O argumento - pode representar a entrada padrão em um dos arquivos. As opções apresentadas seguem o GNU Coreutils; consulte comm --version, comm --help ou man comm para a implementação instalada.

As duas entradas precisam estar ordenadas na mesma localidade, ou locale, que define a comparação de texto. Nos exemplos, LC_ALL=C é usado para a ordenação e para comm. Não ordene numericamente se a comparação espera ordem textual: a sequência de números escritos como 2 e 10 pode ter uma ordem diferente como texto.

Preparar os dados e ler as três colunas

Abra um terminal Bash dedicado ao exercício em uma pasta onde possa criar um diretório. Execute o bloco inteiro: ele cria uma pasta exclusiva e seis arquivos para os exemplos seguintes. && impede que as próximas etapas do bloco continuem após uma falha. Use a mesma sessão e permaneça na pasta criada.

comm_demo=$(mktemp -d ./comm-demo.XXXXXX) &&
cd "$comm_demo" &&
export LC_ALL=C &&
printf 'banana\napple\n' > old.txt &&
printf 'cherry\nbanana\n' > new.txt &&
sort old.txt > old.sorted &&
sort new.txt > new.sorted &&
printf 'apple\napple\napple\n' > dup-old.txt &&
printf 'apple\n' > dup-new.txt &&
comm old.sorted new.sorted

As cópias old.sorted e new.sorted foram produzidas com sort. old.sorted contém apple e banana; new.sorted contém banana e cherry. A saída final representa apple na primeira coluna, banana na terceira e cherry na segunda.

Na saída padrão completa, apple não tem tabulação inicial, banana tem duas e cherry tem uma. As linhas são emitidas na ordem da comparação, não agrupadas em três blocos independentes. A largura visual das tabulações depende do terminal. Para enxergar os separadores no GNU comm, comm --output-delimiter='|' old.sorted new.sorted mostra apple, ||banana e |cherry, uma por linha.

O ajuste export LC_ALL=C vale para esta sessão e seus processos filhos. Ao fechar o terminal dedicado, ele deixa de afetar os comandos futuros; os arquivos permanecem na pasta de prática. Os exemplos leem as entradas, sem regravar os arquivos comparados.

Mostrar somente as linhas comuns

Oculte a primeira e a segunda colunas para manter a terceira:

comm -12 old.sorted new.sorted

O resultado é banana, sem as duas tabulações iniciais da saída completa. Ao ocultar uma coluna, comm também retira seu separador. Os números das opções indicam as colunas a suprimir; não indicam colunas a selecionar.

Mostrar o que entrou ou saiu de uma lista

Para mostrar somente o que existe no segundo arquivo, oculte a primeira e a terceira colunas:

comm -13 old.sorted new.sorted

A saída é cherry. No sentido contrário, comm -23 old.sorted new.sorted mostra apple, presente apenas no primeiro. Se old representa a lista anterior e new a posterior, esses resultados correspondem, respectivamente, a entradas adicionadas e removidas, desde que a interpretação das linhas e das duplicações esteja correta.

Com comm -3 old.sorted new.sorted, a coluna comum é ocultada, mas as duas colunas de diferenças permanecem: apple aparece sem tabulação e cherry com uma. Já comm -123 old.sorted new.sorted suprime todas as colunas e não mostra linhas; isso não significa que os arquivos sejam iguais.

Reproduzir uma comparação mínima

Ainda na pasta exclusiva, execute este exemplo completo, que cria mais dois arquivos pequenos. Eles já estão na ordem textual usada pela sessão:

printf 'apple\nbanana\n' > first.txt
printf 'banana\ncherry\n' > second.txt
comm -12 first.txt second.txt

Saída esperada:

banana

A linha banana é comparada inteira, não como um campo-chave. Se os dados fossem registros com o mesmo identificador e outros campos diferentes, as linhas completas poderiam ser diferentes. Para combinar registros por um campo comum, consulte o guia de join.

Decidir o significado das linhas repetidas

dup-old.txt contém apple três vezes e dup-new.txt uma vez. comm -12 dup-old.txt dup-new.txt mostra uma linha apple, enquanto comm -23 dup-old.txt dup-new.txt mostra duas. Essas duas ocorrências excedentes aparecem na primeira coluna, embora o valor apple também exista no segundo arquivo.

Portanto, com repetições, a primeira coluna não deve ser interpretada automaticamente como uma lista de valores totalmente ausentes do outro arquivo. A comparação emparelha ocorrências iguais e deixa as excedentes no lado correspondente. Esse comportamento foi conferido com GNU comm 8.32 no Bash do Git para Windows.

Se o objetivo é comparar somente a presença de valores distintos, produza cópias com LC_ALL=C sort -u dup-old.txt > dup-old.unique e LC_ALL=C sort -u dup-new.txt > dup-new.unique. Depois, LC_ALL=C comm -23 dup-old.unique dup-new.unique não mostra linhas, porque ambos os conjuntos contêm apple. Preserve as repetições quando elas representarem quantidades importantes.

Verificar erros e salvar resultados

Use LC_ALL=C comm --check-order old.sorted new.sorted quando quiser solicitar explicitamente a validação da ordem. O old.txt original está desordenado: LC_ALL=C comm --check-order old.txt new.sorted falha. Se houver um erro, a saída produzida pode estar incompleta e não deve ser usada como comparação concluída. Ordene cópias corretamente e repita; --nocheck-order não corrige a ordem dos dados.

Após uma execução, echo "$?" mostra o status do comando anterior; consulte-o imediatamente, sem executar outro comando antes. No GNU comm, o status 0 indica término normal mesmo quando há diferenças. Assim, não use o status de sucesso como teste de igualdade entre os arquivos.

Para guardar as linhas comuns em uma saída nova, use (set -C; LC_ALL=C comm --check-order -12 old.sorted new.sorted > common.txt). Após sucesso, confira com cat common.txt. O ajuste set -C fica no comando entre parênteses e impede sobrescrever esse arquivo regular se ele já existir; escolha outro nome nesse caso. Se a execução falhar, um arquivo criado pode conter resultado parcial ou ficar vazio.

Não redirecione para um dos arquivos comparados: o shell pode esvaziá-lo antes de comm ler os dados. Mantenha os originais e valide o término, a ordem e o tratamento das duplicações antes de usar a comparação para atualizar outras listas.

Opções principais

Opção Uso
-1 Oculta a coluna das ocorrências apenas no primeiro arquivo.
-2 Oculta a coluna das ocorrências apenas no segundo arquivo.
-3 Oculta a coluna das ocorrências comuns aos dois arquivos.
--check-order Solicita a verificação da ordem na implementação GNU.

Pergunta frequente

O que significam as três colunas de comm?

Na saída completa, a primeira coluna contém ocorrências sem par no primeiro arquivo, a segunda contém ocorrências sem par no segundo e a terceira contém pares de linhas iguais. Para interpretar o resultado como valores presentes em apenas um conjunto ou em ambos, remova previamente as duplicações em cópias se esse for o objetivo da análise.

Documentação oficial

Consulte a documentação do GNU comm e a página de manual publicada pelo Ubuntu para Coreutils 8.32 para opções, comparação por localidade e verificação da ordem.