Comando diff do Linux
Nos sistemas operacionais do tipo Unix, o comando diff analisa dois arquivos e imprime as linhas diferentes. Em essência, ele fornece um conjunto de instruções sobre como alterar um arquivo para torná-lo idêntico ao segundo arquivo.
Este documento cobre a versão GNU / Linux do diff .
Descrição
O software diff não altera os arquivos que ele compara. No entanto, opcionalmente, pode gerar um script (se a opção -e for especificada) para o programa ed ou ex que pode ser usado para aplicar as alterações.
Por exemplo, considere dois arquivos, file1.txt e file2.txt .
Se file1.txt contiver as quatro linhas de texto a seguir:
Eu preciso comprar maçãs. Eu preciso lavar a roupa. Eu preciso lavar o cachorro. Eu preciso obter o carro detalhado.
… e file2.txt contém estas quatro linhas:
Eu preciso comprar maçãs. Eu preciso lavar a roupa. Eu preciso lavar o carro. Eu preciso detalhar o cachorro.
… então podemos usar o diff para exibir automaticamente para nós quais linhas diferem entre os dois arquivos com este comando:
diff file1.txt file2.txt
… e a saída será:
2,4c2,4 <Eu preciso lavar a roupa. <Eu preciso lavar o cachorro. <Preciso detalhar o carro. --- > Eu preciso lavar a roupa. > Preciso lavar o carro. > Preciso detalhar o cachorro.
Vamos dar uma olhada no que essa saída significa. O importante a lembrar é que, quando diff está descrevendo essas diferenças para você, está fazendo isso em um contexto prescritivo : está lhe dizendo como alterar o primeiro arquivo para que ele corresponda ao segundo arquivo.
A primeira linha da saída do diff conterá:
- números de linhas correspondentes ao primeiro arquivo,
- uma letra ( a para adicionar , c para alterar ou d para excluir ) e
- números de linhas correspondentes ao segundo arquivo.
Em nossa saída acima, ” 2,4c2,4 ” significa: “As linhas 2 a 4 no primeiro arquivo precisam ser suspensas para corresponder às linhas 2 a 4 no segundo arquivo”. Em seguida, ele nos diz quais são essas linhas em cada arquivo:
- Linhas precedidas por um < são linhas do primeiro arquivo;
- linhas precedidas por > são linhas do segundo arquivo.
Os três hífens (” — “) apenas separam as linhas do arquivo 1 e do arquivo 2.
Vejamos outro exemplo. Digamos que nossos dois arquivos sejam assim:
file1.txt :
Eu preciso ir para a loja. Eu preciso comprar algumas maçãs. Quando chegar em casa, lavarei o cachorro.
file2.txt :
Eu preciso ir para a loja. Eu preciso comprar algumas maçãs. Ah, sim, eu também preciso comprar queijo ralado. Quando chegar em casa, lavarei o cachorro.
diff file1.txt file2.txt
Resultado:
2a3 > Ah, sim, eu também preciso comprar queijo ralado.
Aqui, a saída está nos dizendo “Após a linha 2 no primeiro arquivo, uma linha precisa ser dded: linha 3 do segundo arquivo”. Em seguida, ele nos mostra o que é essa linha.
Agora vamos ver como fica quando diff nos diz que precisamos excluir uma linha.
file1 :
Eu preciso ir para a loja. Eu preciso comprar algumas maçãs. Quando chegar em casa, lavarei o cachorro. Eu prometo.
arquivo2 :
Eu preciso ir para a loja. Eu preciso comprar algumas maçãs. Quando chegar em casa, lavarei o cachorro.
Nosso comando:
diff file1.txt file2.txt
A saída:
4d3 <Eu prometo.
Aqui, a saída está nos dizendo “Você precisa excluir a linha 4 no primeiro arquivo para que os dois sejam sincronizados na linha 3 “. Em seguida, ele mostra o conteúdo da linha que precisa ser excluída.
Visualizando Saída diff no Contexto
Os exemplos acima mostram a saída padrão do diff . Ele deve ser lido por um computador, não por um ser humano; portanto, para fins humanos, às vezes ajuda a ver o contexto das mudanças.
O diff GNU , que é a versão que a maioria dos usuários do linux usará, oferece duas maneiras diferentes de fazer isso: “modo de contexto” e “modo unificado”.
Para visualizar diferenças no modo de contexto, use a opção -c . Por exemplo, digamos que file1.txt e file2.txt contêm o seguinte:
file1.txt :
maçãs laranjas kiwis cenouras
file2.txt :
maçãs kiwis cenouras toranjas
Vamos dar uma olhada na saída contextual do diff desses dois arquivos. Nosso comando é:
diff -c arquivo1.txt arquivo2.txt
E nossa saída é assim:
*** file1.txt 2014-08-21 17: 58: 29.764656635 -0400 --- file2.txt 2014-08-21 17: 58: 50.768989841 -0400 *************** *** 1,4 **** maçãs - laranjas kiwis cenouras --- 1,4 ---- maçãs kiwis cenouras + toranjas
As duas primeiras linhas desta saída nos mostram informações sobre nosso arquivo “de” (arquivo 1) e nosso arquivo “para” (arquivo 2). Ele lista o nome do arquivo , a data da modificação e a hora da modificação de cada um de nossos arquivos, um por linha. O arquivo “de” é indicado por ” *** ” e o arquivo “para” é indicado por ” — “.
A linha ” *************** ” é apenas um separador.
A próxima linha possui três asteriscos (” *** “) seguidos por um intervalo de linhas do primeiro arquivo (nesse caso, as linhas 1 a 4 , separadas por vírgula). Depois, quatro asteriscos (” **** “).
Então ele nos mostra o conteúdo dessas linhas. Se a linha não for alterada, será prefixada por dois espaços. Se a linha for alterada, no entanto, será prefixada por um caractere indicativo e um espaço. Os significados dos caracteres são os seguintes:
personagem | significado |
---|---|
! | Indica que esta linha faz parte de um grupo de uma ou mais linhas que precisam ser alteradas. Há um grupo correspondente de linhas prefixadas com ” ! ” No contexto do outro arquivo também. |
+ | Indica uma linha no segundo arquivo que precisa ser adicionada ao primeiro arquivo. |
– | Indica uma linha no primeiro arquivo que precisa ser excluída. |
Após as linhas do primeiro arquivo, há três traços (” — “), depois um intervalo de linhas e quatro traços (” —- “). Isso indica o intervalo de linhas no segundo arquivo que será sincronizado com as alterações no primeiro arquivo.
Se houver mais de uma seção que precise ser alterada, o diff mostrará essas seções uma após a outra. Linhas do primeiro arquivo ainda serão indicadas com ” *** ” e linhas do segundo arquivo com ” — “.
Modo unificado
O modo unificado (a opção -u ) é semelhante ao modo de contexto, mas não exibe nenhuma informação redundante. Aqui está um exemplo, usando os mesmos arquivos de entrada que nosso último exemplo:
file1.txt :
maçãs laranjas kiwis cenouras
file2.txt :
maçãs kiwis cenouras toranjas
Nosso comando:
diff -u arquivo1.txt arquivo2.txt
A saída:
--- file1.txt 2014-08-21 17: 58: 29.764656635 -0400 +++ file2.txt 2014-08-21 17: 58: 50.768989841 -0400 @@ -1,4 +1,4 @@ maçãs laranjas kiwis cenouras + toranjas
A saída é semelhante à acima, mas como você pode ver, as diferenças são “unificadas” em um conjunto.
Localizando diferenças no conteúdo do diretório
diff também pode comparar diretórios fornecendo nomes de diretórios em vez de nomes de arquivos. Veja a seção Exemplos .
Usando diff para criar um script de edição
A opção -e diz ao diff para gerar um script, que pode ser usado pelos programas de edição ed ou ex , que contém uma sequência de comandos. Os comandos são uma combinação de c (alterar), a (adicionar) e d (excluir) que, quando executados pelo editor, modificam o conteúdo do arquivo1 (o primeiro arquivo especificado na linha de comando diff ) para que ele corresponda o conteúdo do arquivo2 (o segundo arquivo especificado).
Digamos que temos dois arquivos com o seguinte conteúdo:
file1.txt :
Era uma vez uma garota chamada Perséfone. Ela tinha cabelos pretos. Ela amava a mãe mais do que tudo. Ela gostava de sentar ao sol com sua gata, Daisy. Ela sonhava em ser pintora quando cresceu.
file2.txt
Era uma vez uma garota chamada Perséfone. Ela tinha cabelos ruivos. Ela adorava biscoitos de chocolate mais do que tudo. Ela gostava de sentar ao sol com sua gata, Daisy. Ela olhava para as nuvens e sonhava em ser um padeiro mundialmente famoso.
Podemos executar o seguinte comando para analisar os dois arquivos com diff e produzir um script para criar um arquivo idêntico a file2.txt a partir do conteúdo de file1.txt :
diff -e arquivo1.txt arquivo2.txt
… e a saída ficará assim:
5c Ela olhava para as nuvens e sonhava em ser um padeiro mundialmente famoso. . 2,3c Ela tinha cabelos ruivos. Ela adorava biscoitos de chocolate mais do que tudo. .
Observe que as alterações estão listadas na ordem inversa: as alterações mais próximas ao final do arquivo são listadas primeiro e as alterações mais próximas ao início do arquivo são listadas por último. Esse pedido é para preservar a numeração das linhas; se fizermos as alterações no início do arquivo primeiro, isso poderá alterar os números de linha posteriormente no arquivo. Portanto, o script começa no final e funciona ao contrário.
Aqui, o script está informando o programa de edição: “mude a linha 5 para (a linha seguinte) e altere as linhas 2 a 3 para (as duas linhas seguintes)”.
Em seguida, devemos salvar o script em um arquivo. Podemos redirecionar a saída diff para um arquivo usando o operador > , assim:
diff -e arquivo1.txt arquivo2.txt> my-ed-script.txt
Este comando não exibirá nada na tela (a menos que haja um erro); em vez disso, a saída é redirecionada para o arquivo my-ed-script.txt . Se my-ed-script.txt não existir, ele será criado; se já existir, será substituído .
Se agora verificarmos o conteúdo de my-ed-script.txt com o comando cat …
gato my-ed-script.txt
… veremos o mesmo script que vimos exibido acima.
Ainda falta uma coisa: precisamos do script para dizer ao ed para realmente escrever o arquivo. Tudo o que está faltando no script é o comando w , que gravará as alterações. Podemos adicionar isso ao nosso script repetindo a letra ” w ” e usando o operador >> para adicioná-lo ao nosso arquivo. (O operador >> é semelhante ao operador > . Ele redireciona a saída para um arquivo, mas, em vez de sobrescrever o arquivo de destino, é anexado ao final do arquivo.) O comando se parece com o seguinte:
eco "w" >> meu-ed-script.txt
Agora, podemos verificar se nosso script foi alterado executando o comando cat novamente:
gato my-ed-script.txt
5c Ela olhava para as nuvens e sonhava em ser um padeiro mundialmente famoso. . 2,3c Ela tinha cabelos ruivos. Ela adorava biscoitos de chocolate mais do que tudo. . W
Agora, nosso script, quando emitido para ed , fará as alterações e gravará as alterações no disco.
Então, como é que vamos fazer isso?
Podemos emitir esse script para edição com o seguinte comando, dizendo para substituir o arquivo original. O traço (” – “) instrui o ed a ler da entrada padrão e o operador < direciona nosso script para essa entrada. Em essência, o sistema insere o que estiver em nosso script como entrada para o programa de edição. O comando fica assim:
ed - arquivo1.txt <meu-ed-script.txt
Este comando não exibe nada, mas se observarmos o conteúdo do nosso arquivo original …
cat file1.txt
Era uma vez uma garota chamada Perséfone. Ela tinha cabelos ruivos. Ela adorava biscoitos de chocolate mais do que tudo. Ela gostava de sentar ao sol com sua gata, Daisy. Ela olhava para as nuvens e sonhava em ser um padeiro mundialmente famoso.
… podemos ver que o arquivo1.txt agora corresponde exatamente ao arquivo2.txt .
Aviso! Neste exemplo, ed substituiu o conteúdo do nosso arquivo original, file1.txt . Depois de executar o script, o texto original de file1.txt desaparece. Portanto, certifique-se de entender o que está fazendo antes de executar esses comandos!
Opções de diff comumente usadas
Aqui estão algumas opções diff úteis para anotar:
-b | Ignore quaisquer alterações que alterem apenas a quantidade de espaço em branco (como espaços ou tabulações). |
-W | Ignore completamente os espaços em branco. |
-B | Ignore linhas em branco ao calcular diferenças. |
-y | Exibe a saída em duas colunas. |
Estas são apenas algumas das opções de diferenças mais usadas. A seguir, é apresentada uma lista completa das opções diff e suas funções.
Sintaxe
diff [ OPÇÃO ] ... ARQUIVOS
Opções
–normal | Emita um diff “normal”, que é o padrão. | ||||||
-q , –brief | Produza saída somente quando os arquivos diferirem. Se não houver diferenças, não produza nada. | ||||||
-s, –report-identical-files | Relate quando dois arquivos são iguais. | ||||||
-c , -C NUM , –context [ = NUM ] | Forneça NUM (padrão 3 ) linhas de contexto. | ||||||
-u, -U NUM, –unified[=NUM] | Forneça NUM (padrão 3 ) linhas de contexto unificado. | ||||||
-e , –ed | Saída de um script ed . | ||||||
-n , –rcs | Saída de um formato RCS diff. | ||||||
-y, –side by side | Formate a saída em duas colunas. | ||||||
-W , –width = NUM | Saída na maioria das colunas de impressão NUM (padrão 130 ). | ||||||
–left-column | Saída apenas a coluna esquerda de linhas comuns. | ||||||
–suppress-common-lines | Não produza linhas comuns entre os dois arquivos. | ||||||
-p, –show-c-function | Para arquivos que contêm código C, mostre também cada alteração de função C. | ||||||
-F , –show-function-line = RE | Mostrar a linha mais recente correspondente à expressão regular RE . | ||||||
–label LABEL | Ao exibir a saída, use o rótulo LABEL em vez do nome do arquivo. Esta opção pode ser emitida mais de uma vez para vários rótulos. | ||||||
-t , –expand-tabs | Expanda guias para espaços na saída. | ||||||
-T , – guia inicial | Para alinhar as guias, adicione uma guia, se necessário. | ||||||
–tabsize = NUM | Defina uma tabulação como NUM (padrão 8 ) colunas. | ||||||
–suppress-blank-empty | Suprima espaços ou tabulações antes das linhas de saída vazias. | ||||||
-l , –paginate | Passe a saída pelo pr para paginar . | ||||||
-r , –recursive | Compare recursivamente todos os subdiretórios encontrados. | ||||||
-N, –new-file | Se um arquivo especificado não existir, execute o diff como se fosse um arquivo vazio. | ||||||
–unidirectional-new-file | O mesmo que -n , mas só se aplica ao primeiro arquivo. | ||||||
–ignore-file-name-case | Ignore maiúsculas e minúsculas ao comparar nomes de arquivos. | ||||||
–no-ignore-file-name-case | Considere o caso ao comparar nomes de arquivos. | ||||||
-x , –exclude = PAT | Excluir arquivos que correspondam ao padrão de nome de arquivo PAT . | ||||||
-X, –exclude-from=FILE | Excluir arquivos que correspondam a qualquer padrão de nome de arquivo no arquivo FILE . | ||||||
-S , –starting-file = ARQUIVO | Comece com o arquivo FILE ao comparar diretórios . | ||||||
–from-file = FILE1 | Compare FILE1 a todos os operandos ; FILE1 pode ser um diretório. | ||||||
–to-file=FILE2 | Compare todos os operandos ao FILE2 ; FILE2 pode ser um diretório. | ||||||
-i , –ignore-case | Ignore as diferenças entre maiúsculas e minúsculas no conteúdo do arquivo. | ||||||
-E , –ignore-tab-expansion | Ignore as alterações devido à expansão da guia . | ||||||
-b , –ignore-space-change | Ignore as alterações na quantidade de espaço em branco . | ||||||
-w , –ignore-all-space | Ignore todo o espaço em branco. | ||||||
-B , –ignore-blank-lines | Ignore as alterações cujas linhas estão todas em branco. | ||||||
-I , –ignore-matching-lines = RE | Ignore as alterações cujas linhas correspondem à expressão regular RE . | ||||||
-a , –text | Trate todos os arquivos como texto. | ||||||
–strip-trailing-cr | Retorno de carro à direita da faixa na entrada. | ||||||
-D , –ifdef = NAME | Arquivo de saída mesclado com ” #ifdef NAME ” diffs. | ||||||
– GTYPE -group -format = GFMT | Formate grupos de entrada GTYPE com GFMT . | ||||||
–line-format = LFMT | Formate todas as linhas de entrada com LFMT . | ||||||
– LTYPE -line-format = LFMT | Formate as linhas de entrada LTYPE com LFMT . Essas opções de formato fornecem controle refinado sobre a saída do diff , generalizando -D / –ifdef . LTYPE é antigo , novo ou inalterado . GTYPE pode ser qualquer um dos valores LTYPE ou o valor alterado . GFMT (mas não LFMT ) pode conter:
| ||||||
% [ – ] [ LARGURA ] [ . [ PREC ]] { doxX } CARTA | especificação printf- style para LETTER |
LETRA s são as seguintes para o novo grupo, em minúsculas para o grupo antigo:
F | Número da primeira linha. |
L | Número da última linha |
N | Número de linhas = L – F + 1. |
E | F – 1 |
M | L + 1 |
% ( A = B ? T : E ) | Se A for igual a B, então T mais E. |
LFMT (apenas) pode conter:
%L | Conteúdo da linha. |
%l | Conteúdo da linha, excluindo qualquer nova linha à direita. |
% [ – ] [ LARGURA ] [ . [ PREC ]] { doxX } n | especificação printf- style para o número da linha de entrada. |
GFMT e LFMT podem conter:
%% | Um % literal . |
% c ‘ C ‘ | O único caractere C. |
% c ‘\ OOO’ | O personagem com código octal OOO. |
C | O caractere C (outros caracteres se representam). |
-d , –minimal | Tente encontrar um conjunto menor de alterações. |
–horizon-lines = NUM | Mantenha NUM linhas do prefixo e sufixo comuns. |
–speed-large-files | Suponha arquivos grandes e muitas pequenas alterações espalhadas. |
–help | Exiba uma mensagem de ajuda e saia. |
-v , –version | Informações de versão de saída e saída. |
FILES assume o formato ” FILE1 FILE2 ” ou ” DIR1 DIR2 ” ou ” DIR FILE …” ou ” FILE … DIR “.
Se as opções –from-file ou –to-file forem fornecidas, não haverá restrições em FILE (s). Se um arquivo é um traço (” – “), o diff lê da entrada padrão .
O status de saída é 0 se as entradas forem iguais, 1 se diferente ou 2 se o diff encontrar algum problema.
Exemplos
Aqui está um exemplo do uso do diff para examinar as diferenças entre dois arquivos lado a lado usando a opção -y , considerando os seguintes arquivos de entrada:
file1.txt:
maçãs laranjas kiwis cenouras
file2.txt:
maçãs kiwis cenouras toranjas
diff -y arquivo1.txt arquivo2.txt
Resultado:
maçãs maçãs laranjas < kiwis kiwis cenouras cenouras > toranjas
E, como prometido, aqui está um exemplo do uso do diff para comparar dois diretórios:
diff dir1 dir2
Resultado:
Somente em dir1: tab2.gif Somente no dir1: tab3.gif Somente em dir1: tab4.gif Somente no dir1: tape.htm Somente no dir1: tbernoul.htm Somente no dir1: tconner.htm Somente no dir1: tempbus.psd
Comandos relacionados
bdiff – identifique as diferenças entre dois arquivos muito grandes.
cmp – Compare dois arquivos byte por byte.
comm – Compare dois arquivos classificados linha por linha.
dircmp – Compare o conteúdo de dois diretórios, listando arquivos exclusivos.
ed – Um simples editor de texto.
pr – Formate um arquivo de texto para impressão.
ls – lista o conteúdo de um diretório ou diretórios.
sdiff – Compare dois arquivos, lado a lado.