comm e join: Comparando e Unindo Arquivos

comm e join: Comparando e Unindo Arquivos

O Que Voce Vai Aprender

  • Como extrair linhas comuns e diferencas entre dois arquivos com comm
  • Como unir dois arquivos horizontalmente por uma chave compartilhada com join
  • Como evitar falhas relacionadas a ordenacao como linhas ausentes ou avisos not sorted

Resumo Rapido

  • Quer linhas comuns / diferencas linha por linha --> comm
  • Quer unir duas tabelas por uma coluna chave (como SQL JOIN) --> join
  • Ambos exigem entrada ordenada -- isso e inegociavel

Premissas (ambiente)

  • GNU coreutils (Ubuntu / maioria das distribuicoes Linux)
  • comm e join vem com o coreutils. Nenhuma instalacao extra necessaria

O que e comm e o que ele faz?

Conclusao: comm compara dois arquivos ordenados linha por linha e imprime "somente esquerdo / somente direito / comum" em tres colunas.

comm compara dois arquivos ordenados e organiza o resultado em tres colunas.

  • Coluna 1: linhas somente no arquivo1
  • Coluna 2: linhas somente no arquivo2
  • Coluna 3: linhas em ambos (linhas comuns)

Aqui estao 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 posicao da coluna e indicada pela indentacao de tab. apple esta somente no esquerdo (coluna 1), banana e cherry estao em ambos (coluna 3, dois tabs), e date esta somente no direito (coluna 2, um tab).

Por que comm exige entrada ordenada?

Conclusao: comm usa um merge simples que le ambos os arquivos linha por linha, entao entrada desordenada faz com que ele perca linhas comuns.

comm avanca por ambos os arquivos simultaneamente a partir do topo. Se a ordem estiver quebrada, ele nao consegue detectar linhas correspondentes corretamente e a saida fica incorreta. Entrada desordenada dispara este aviso:

comm: file 1 is not in sorted order

Sempre execute sort primeiro. A substituicao de processo evita arquivos temporarios:

$ comm <(sort a.txt) <(sort b.txt)

A colacao do sort e dependente do locale. Se comm e sort discordarem na ordenacao, os resultados falham. Em caso de duvida, fixe a ordem com LC_ALL=C sort para estabilidade.

Como selecionar colunas especificas do comm?

Conclusao: Use -1, -2, -3 para suprimir a coluna correspondente. O numero refere-se a coluna que voce remove.

As opcoes especificam a coluna a suprimir, nao a coluna a exibir.

Objetivo Comando Coluna restante
Somente linhas comuns comm -12 a b Coluna 3
Somente diferencas 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 memorizacao: os numeros dizem "remova estas colunas." Para manter somente linhas comuns, remova as colunas 1 e 2 com -12.

O que e join e como e diferente de comm?

Conclusao: 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 unica linha. A chave padrao e 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, entao sao unidas. 3 carol e 4 marketing nao tem correspondencia e nao sao impressos (inner join).

join tambem 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 juncao e o delimitador?

Conclusao: Use -t para o delimitador, -1 / -2 para a coluna chave de cada arquivo, e -o para os campos de saida.

Ajuste estes quando o delimitador for diferente (como CSV) ou a chave nao 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 e a coluna 1; em depts.csv a chave e a coluna 2. O delimitador e virgula.

$ join -t, -1 1 -2 2 users.csv depts.csv
1,alice,tokyo,sales
2,bob,osaka,engineering
  • -t,: define o delimitador como virgula
  • -1 1: a chave no arquivo1 e a coluna 1
  • -2 2: a chave no arquivo2 e a coluna 2

Use -o para especificar os campos de saida. -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 correspondencia (outer join)?

Conclusao: Use -a para tambem imprimir linhas sem par. -a 1 e um left outer join; -a 1 -a 2 e um full outer join.

Um inner join descarta linhas sem correspondencia. Use -a para mante-las.

$ join -a 1 users.txt depts.txt
1 alice sales
2 bob engineering
3 carol

3 carol nao tem correspondencia em depts.txt, mas -a 1 a mantem (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 saida.

comm vs join: qual usar

Conclusao: Use comm para diferencas de conjuntos de linhas e join para mesclagens baseadas em chave. Ambos exigem entrada ordenada.

Objetivo Comando
Encontrar linhas comuns / diferencas comm
Unir duas tabelas por chave comum join
Deduplicar / ordenar (pre-processamento) sort

Armadilhas a evitar

  • Passar entrada desordenada para comm / join (linhas sao descartadas silenciosamente)
  • Misturar locales entre comm e sort (incompatibilidade de ordenacao quebra resultados)
  • Esquecer as opcoes de coluna chave (-1 / -2) do join e usar o padrao coluna 1