Comparar arquivos é uma tarefa comum no dia a dia de quem trabalha com programação, configuração de sistemas ou manipulação de dados. O Linux oferece ferramentas poderosas para essa finalidade, cada uma com suas particularidades. Nesta aula, vamos explorar três utilitários essenciais: diff, comm e cmp, além de uma introdução ao patch, que é usado para aplicar diferenças. Ao final, você terá um repertório sólido para analisar e sincronizar arquivos de forma eficiente.

Entender as diferenças entre essas ferramentas é crucial: diff mostra as diferenças linha a linha, comm compara arquivos já ordenados e cmp compara byte a byte. Cada uma tem seu uso específico, e saber escolher a ferramenta certa economiza tempo e evita erros.

diff

O comando diff é o mais conhecido para comparar arquivos de texto. Ele analisa dois arquivos e exibe as linhas que diferem entre eles, indicando como transformar o primeiro arquivo no segundo. A saída padrão é um conjunto de comandos que podem ser interpretados por humanos ou por outras ferramentas.

A sintaxe básica é diff [opções] arquivo1 arquivo2. Sem opções, a saída mostra as diferenças em um formato chamado "normal", que inclui instruções como a (adicionar), c (alterar) e d (deletar). Por exemplo, considere dois arquivos:

$ cat arquivo1.txt
linha1
linha2
linha3
$ cat arquivo2.txt
linha1
linha2 modificada
linha4

Executando diff arquivo1.txt arquivo2.txt, obtemos:

2,3c2,3
< linha2
< linha3
---
> linha2 modificada
> linha4

Isso indica que as linhas 2 e 3 do primeiro arquivo foram alteradas para as linhas 2 e 3 do segundo. O < representa o primeiro arquivo e o > o segundo.

O diff oferece várias opções úteis. A opção -u gera uma saída unificada, que é mais compacta e amplamente usada em sistemas de controle de versão. A opção -c gera uma saída com contexto, mostrando linhas ao redor das diferenças. Já a opção -i ignora diferenças de maiúsculas/minúsculas, e -w ignora espaços em branco.

$ diff -u arquivo1.txt arquivo2.txt
--- arquivo1.txt
+++ arquivo2.txt
@@ -1,4 +1,4 @@
 linha1
-linha2
-linha3
+linha2 modificada
+linha4

O diff também pode ser usado recursivamente com a opção -r para comparar diretórios inteiros. Isso é muito útil para verificar mudanças em projetos de software.

Outra ferramenta relacionada é o diff3, que compara três arquivos e é útil para mesclar alterações, mas não será abordado em detalhes aqui.

comm

O comando comm compara dois arquivos que devem estar ordenados (lexicograficamente). Ele produz três colunas na saída: a primeira coluna contém linhas exclusivas do primeiro arquivo, a segunda coluna linhas exclusivas do segundo, e a terceira coluna linhas comuns aos dois. Por padrão, todas as colunas são exibidas, mas é possível suprimir colunas com as opções -1, -2 e -3.

Por exemplo, considere os arquivos:

$ cat lista1.txt
banana
laranja
maçã
$ cat lista2.txt
banana
pera
uva

Como estão ordenados (em ordem alfabética, com acentos), podemos executar:

$ comm lista1.txt lista2.txt
banana
	laranja
		maçã
	pera
	uva

A saída mostra que "banana" está nas duas listas (na terceira coluna, indicada por dois tabs), "laranja" e "maçã" são exclusivos do primeiro arquivo (primeira coluna, um tab), e "pera" e "uva" são exclusivos do segundo (segunda coluna).

Para obter apenas as linhas comuns, use comm -12 arquivo1 arquivo2. Para linhas exclusivas do primeiro, comm -23; para exclusivas do segundo, comm -13.

$ comm -12 lista1.txt lista2.txt
banana

O comm é particularmente útil quando você já tem arquivos ordenados, por exemplo, gerados por sort. Se os arquivos não estiverem ordenados, o resultado pode ser imprevisível, então é recomendável ordená-los antes.

cmp

Enquanto diff e comm trabalham com linhas de texto, o cmp compara arquivos byte a byte. Ele é útil para verificar se dois arquivos são idênticos, independentemente do tipo (binário ou texto). A sintaxe é cmp [opções] arquivo1 arquivo2.

Por padrão, o cmp não produz saída se os arquivos forem idênticos, e retorna o código de saída 0. Se forem diferentes, ele exibe a primeira posição em que diferem e retorna o código 1. Se ocorrer um erro, retorna 2.

$ cmp arquivo1.txt arquivo2.txt
arquivo1.txt arquivo2.txt diferem: byte 9, linha 2
$ echo $?
1

A opção -l (ou --verbose) exibe todas as diferenças, mostrando a posição e o valor de cada byte em octal. A opção -s (ou --silent) suprime toda a saída, apenas retornando o código de saída, o que é útil em scripts.

$ cmp -s arquivo1.txt arquivo2.txt; echo $?
1

O cmp é eficiente para verificar se dois binários são idênticos, como em testes de integridade. No entanto, para textos, o diff fornece informações mais detalhadas.

patch (visão geral)

O comando patch é usado para aplicar um arquivo de diferenças (gerado pelo diff) a um ou mais arquivos originais, transformando-os na versão modificada. É amplamente usado para distribuir alterações em projetos de software, como em listas de discussão ou correções de segurança.

O fluxo típico é: gerar um arquivo de diferenças com diff (normalmente no formato unificado) e depois usar patch para aplicá-lo. Por exemplo:

$ diff -u arquivo_original.txt arquivo_modificado.txt > mudancas.patch
$ patch arquivo_original.txt < mudancas.patch
patching file arquivo_original.txt

O patch também pode ser usado com a opção -p para controlar quantos componentes de diretório devem ser ignorados ao aplicar o patch, especialmente quando os caminhos nos cabeçalhos do diff incluem diretórios.

Para reverter um patch, use a opção -R. Isso restaura o arquivo ao estado original.

$ patch -R arquivo_original.txt < mudancas.patch

É importante verificar se o patch foi aplicado corretamente. O comando patch tenta aplicar o patch mesmo se as linhas de contexto não coincidirem exatamente, usando heurísticas, mas é recomendável fazer backup dos arquivos antes de aplicar.

Boas práticas e observações finais

Ao trabalhar com comparação de arquivos, algumas boas práticas podem evitar dor de cabeça:

  • Use diff -u para gerar patches mais legíveis e que podem ser aplicados com patch.
  • Sempre verifique o código de saída dos comandos em scripts, especialmente com cmp -s e diff -q (que apenas informa se os arquivos diferem).
  • Para arquivos grandes, o cmp é mais rápido que o diff para verificação de igualdade, pois não processa linhas.
  • Quando usar comm, garanta que os arquivos estejam ordenados, por exemplo, usando sort -u para remover duplicatas.
  • Em projetos com controle de versão (git, SVN), as ferramentas de diff integradas são mais poderosas, mas conhecer os comandos básicos é fundamental para depuração e automação.

Dominar essas ferramentas aumenta sua produtividade no terminal e é essencial para tarefas como revisão de código, sincronização de arquivos e análise de logs.

Referências

Exercícios

  1. Crie dois arquivos de texto com algumas linhas diferentes e use diff para exibir as diferenças no formato unificado. Explique o significado de cada parte da saída.

    ✓ Resposta: O formato unificado começa com cabeçalhos indicando os arquivos e as linhas afetadas. Por exemplo:
    --- arquivo1.txt
    +++ arquivo2.txt
    @@ -1,4 +1,4 @@
     linha1
    -linha2
    -linha3
    +linha2 modificada
    +linha4
    
    O trecho @@ -1,4 +1,4 @@ indica que as linhas 1 a 4 do arquivo original correspondem às linhas 1 a 4 do novo. Linhas precedidas por - são removidas, e por + são adicionadas. Linhas sem prefixo são contexto.
  2. Dado dois arquivos ordenados, use comm para listar apenas as linhas que estão no primeiro arquivo, mas não no segundo. Mostre o comando e a saída.

    ✓ Resposta: Use comm -23 arquivo1 arquivo2. Por exemplo, se arquivo1 contém a b c e arquivo2 contém a c, a saída será b, pois está apenas no primeiro.
  3. Escreva um script Bash que verifique se dois arquivos são idênticos usando cmp -s e imprima uma mensagem adequada. Inclua tratamento de erro caso os arquivos não existam.

    ✓ Resposta:
    #!/bin/bash
    if [[ $# -ne 2 ]]; then
        echo "Uso: $0 arquivo1 arquivo2"
        exit 1
    fi
    if [[ ! -f "$1" || ! -f "$2" ]]; then
        echo "Erro: um dos arquivos não existe."
        exit 1
    fi
    if cmp -s "$1" "$2"; then
        echo "Os arquivos são idênticos."
    else
        echo "Os arquivos são diferentes."
    fi
    
  4. Gere um patch a partir de dois arquivos usando diff -u e aplique-o a um terceiro arquivo (que deve ser idêntico ao original). Verifique se a aplicação foi bem-sucedida.

    ✓ Resposta:
    $ diff -u original.txt modificado.txt > mudancas.patch
    $ cp original.txt copia.txt
    $ patch copia.txt < mudancas.patch
    patching file copia.txt
    $ diff -q copia.txt modificado.txt && echo "Patch aplicado com sucesso!"
    
  5. Explique a diferença entre diff, comm e cmp e dê um exemplo de uso para cada um.

    ✓ Resposta: diff mostra diferenças linha a linha em arquivos de texto, útil para ver alterações. comm compara arquivos ordenados e mostra linhas exclusivas/comuns em colunas. cmp compara byte a byte, ideal para binários. Exemplos: diff -u old new, comm -12 sorted1 sorted2, cmp -s file1 file2.