comm e join: Comparando e Unindo Arquivos
O Que Você Vai Aprender
- Como extrair linhas comuns e diferenças entre dois arquivos com
comm - Como unir dois arquivos horizontalmente por uma chave compartilhada com
join - Como evitar falhas relacionadas a ordenação como linhas ausentes ou avisos
not sorted
Resumo Rápido
- Quer linhas comuns / diferenças linha por linha -->
comm - Quer unir duas tabelas por uma coluna chave (como SQL JOIN) -->
join - Ambos exigem entrada ordenada -- isso é inegociável
Premissas (ambiente)
- GNU coreutils (Ubuntu / maioria das distribuições Linux)
commejoinvêm com o coreutils. Nenhuma instalação extra necessária
O que é comm e o que ele faz?
Conclusão: comm compara dois arquivos ordenados linha por linha e imprime "somente esquerdo / somente direito / comum" em três colunas.
comm compara dois arquivos ordenados e organiza o resultado em três colunas.
- Coluna 1: linhas somente no arquivo1
- Coluna 2: linhas somente no arquivo2
- Coluna 3: linhas em ambos (linhas comuns)
Aqui estão dois arquivos de exemplo:
$ cat a.txt apple banana cherry $ cat b.txt banana cherry date
$ comm a.txt b.txt
apple banana cherry date
A posição da coluna é indicada pela indentação de tab. apple está somente no esquerdo (coluna 1), banana e cherry estão em ambos (coluna 3, dois tabs), e date está somente no direito (coluna 2, um tab).
Por que comm exige entrada ordenada?
Conclusão: comm usa um merge simples que lê ambos os arquivos linha por linha, então entrada desordenada faz com que ele perca linhas comuns.
comm avança por ambos os arquivos simultaneamente a partir do topo. Se a ordem estiver quebrada, ele não consegue detectar linhas correspondentes corretamente e a saída fica incorreta. Entrada desordenada dispara este aviso:
comm: file 1 is not in sorted order
Sempre execute sort primeiro. A substituição de processo evita arquivos temporários:
$ comm <(sort a.txt) <(sort b.txt)
A colação do sort é dependente do locale. Se comm e sort discordarem na ordenação, os resultados falham. Em caso de dúvida, fixe a ordem com LC_ALL=C sort para estabilidade.
Como selecionar colunas específicas do comm?
Conclusão: Use -1, -2, -3 para suprimir a coluna correspondente. O número refere-se à coluna que você remove.
As opções especificam a coluna a suprimir, não a coluna a exibir.
| Objetivo | Comando | Coluna restante |
|---|---|---|
| Somente linhas comuns | comm -12 a b |
Coluna 3 |
| Somente diferenças | comm -3 a b |
Colunas 1 e 2 |
| Linhas somente no arquivo1 | comm -23 a b |
Coluna 1 |
| Linhas somente no arquivo2 | comm -13 a b |
Coluna 2 |
$ comm -12 a.txt b.txt banana cherry
$ comm -23 a.txt b.txt apple
Dica de memorização: os números dizem "remova estas colunas." Para manter somente linhas comuns, remova as colunas 1 e 2 com -12.
O que é join e como é diferente de comm?
Conclusão: join mescla linhas de dois arquivos por uma coluna chave compartilhada, equivalente a um INNER JOIN do SQL.
Enquanto comm compara linhas inteiras, join mescla linhas cujo campo chave corresponde em uma única linha. A chave padrão é o primeiro campo de cada linha.
$ cat users.txt 1 alice 2 bob 3 carol $ cat depts.txt 1 sales 2 engineering 4 marketing
$ join users.txt depts.txt
1 alice sales 2 bob engineering
As chaves 1 e 2 existem em ambos os arquivos, então são unidas. 3 carol e 4 marketing não têm correspondência e não são impressos (inner join).
join também exige entrada ordenada pela coluna chave. Entrada desordenada produz um aviso join: ... is not sorted e descarta linhas. Assim como comm, execute sort primeiro.
Como definir campos de junção e o delimitador?
Conclusão: Use -t para o delimitador, -1 / -2 para a coluna chave de cada arquivo, e -o para os campos de saída.
Ajuste estes quando o delimitador for diferente (como CSV) ou a chave não for a primeira coluna.
$ cat users.csv 1,alice,tokyo 2,bob,osaka $ cat depts.csv sales,1 engineering,2
Em users.csv a chave é a coluna 1; em depts.csv a chave é a coluna 2. O delimitador é vírgula.
$ join -t, -1 1 -2 2 users.csv depts.csv
1,alice,tokyo,sales 2,bob,osaka,engineering
-t,: define o delimitador como vírgula-1 1: a chave no arquivo1 é a coluna 1-2 2: a chave no arquivo2 é a coluna 2
Use -o para especificar os campos de saída. -o 1.1,1.2,2.1 significa "colunas 1 e 2 do arquivo1, depois coluna 1 do arquivo2." Liste-os como <arquivo>.<campo>.
Como manter linhas sem correspondência (outer join)?
Conclusão: Use -a para também imprimir linhas sem par. -a 1 é um left outer join; -a 1 -a 2 é um full outer join.
Um inner join descarta linhas sem correspondência. Use -a para mantê-las.
$ join -a 1 users.txt depts.txt
1 alice sales 2 bob engineering 3 carol
3 carol não tem correspondência em depts.txt, mas -a 1 a mantém (com o campo ausente vazio). Para preencher a lacuna, combine -e e -o.
$ join -a 1 -e '-' -o '1.1,1.2,2.2' users.txt depts.txt
1 alice sales 2 bob engineering 3 carol -
-e '-' preenche campos ausentes com -, e -o fixa as colunas de saída.