Como diferencio dois arquivos de texto no Windows Powershell?

96

Eu tenho dois arquivos de texto e quero encontrar as diferenças entre eles usando o Windows Powershell. Existe algo semelhante à ferramenta diff Unix disponível? Ou existe outra maneira de não considerar?

Eu tentei comparar objeto, mas obtenha esta saída enigmática:

PS C:\> compare-object one.txt two.txt

InputObject                                                 SideIndicator
-----------                                                 -------------
two.txt                                                     =>
one.txt                                                     <=
Brian Willis
fonte

Respostas:

101

Eu mesmo descobri. Como o Powershell trabalha com objetos .net em vez de texto, você precisa usar get-content para expor o conteúdo dos arquivos de texto. Então, para executar o que eu estava tentando fazer na pergunta, use:

compare-object (get-content one.txt) (get-content two.txt)
Brian Willis
fonte
1
Fiquei muito surpreso quando tentei comparar dois arquivos: uma matriz não classificada de números e a mesma matriz depois de ordená-los. Não há saída, apesar dos arquivos serem muito diferentes. Aparentemente, compare-object não considera ordem.
Cgmb #
1
@cgmb - Você pode -SyncWindow 0corrigir isso, acredito, embora não tenha certeza se foi introduzido apenas recentemente. Não é particularmente inteligente sobre isso, no entanto.
James Ruskin
32

Uma maneira mais simples de fazer isso é escrever:

diff (cat file1) (cat file2)
Alex Y.
fonte
16
Diff e cat são apenas aliases para Comparar Objeto e Obter Conteúdo no PowerShell. É a mesma coisa.
Shawn Melton
4
apesar deste ser o mesmo que a resposta aceita, eu gosto de usar esta sintaxe mais
Elias W. Gagne
Observe que ele não se comporta como * nix diff, como outras respostas aqui observadas. E quando usei uma expressão mais complexa no lugar de catobtive uma saída incorreta, por isso, juntarei as outras pessoas na recomendação para evitar isso no PowerShell se você vier do * nix.
Nickolay
29

Ou você pode usar o fccomando DOS da seguinte forma (isso mostra a saída de ambos os arquivos para que você precise verificar as diferenças):

fc.exe filea.txt fileb.txt > diff.txt

fcé um alias para o cmdlet Format-Custom, certifique-se de inserir o comando comofc.exe . Observe que muitos utilitários do DOS não lidam com a codificação UTF-8.

Você também pode gerar um processo CMD e executá fc-lo.

start cmd "/c  ""fc filea.txt fileb.txt >diff.txt"""

Isso instrui o PowerShell a iniciar um processo com o programa 'cmd' usando os parâmetros entre aspas. Nas aspas, é a opção '/ c' cmd para executar o comando e finalizar. O comando real a ser executado pelo cmd no processo está fc filea.txt fileb.txtredirecionando a saída para o arquivo diff.txt.

Você pode usar o DOS fc.exede dentro do PowerShell.

phord350
fonte
2
+1 para trazer para fora o DOS ^ _ ^
Jeff Bridgman
1
"fc" não estava funcionando para mim e não percebi que precisava especificá-lo como "fc.exe" para diferenciá-lo do formato personalizado. Exatamente o que eu estava procurando. Obrigado.
Xonatron 17/09
Talvez eu seja um filisteu completo, mas isso me parece muito mais útil. Resolveu meu problema muito bem.
AJ.
O único problema é que ele odeia o unicode.
iCodeSometime
7

O diff on * nix não faz parte do shell, mas um aplicativo separado.

Existe algum motivo para você não poder usar o diff.exe no PowerShell?

Você pode baixar uma versão do pacote UnxUtils ( http://unxutils.sourceforge.net/ )

Mikeage
fonte
10
Como o PowerShell está incluído agora, nada para baixar e instalar.
Bratch
Acabei de usar git diff, porque já o tinha instalado. Nem fc.exenem Compare-Objectproduziu a saída que eu esperava.
Raziel
4

O compare-object (também conhecido como diff) é patético se você espera que se comporte como um diff unix. Eu tentei o diff (gc file1) (gc file2) e, se uma linha é muito longa, não consigo ver o diff real e, mais importante, não sei dizer em qual número de linha o diff está.

Quando tento adicionar -passthru, agora vejo a diferença, mas perco em qual arquivo está a diferença e ainda não recebo o número da linha.

Meu conselho, não use o PowerShell para encontrar diferenças nos arquivos. Como outra pessoa notou, o fc funciona e funciona um pouco melhor do que o objeto comparar, e ainda melhor é baixar e usar ferramentas reais, como o emulador unix que o Mikeage mencionou.

Marc Towersap
fonte
Também parece fazer uma comparação definida (ou seja, ignorando a ordem) como -SyncWindowé maxint por padrão. Definir isso como 0 também não funciona diff... E quando eu passei um pipe (... | select-object ...)como entrada, ele imprimiu bobagens, então desisti.
Nickolay
3

Como outros observaram, se você estava esperando uma saída diff unix-y, o uso do apelido diff do powershell o deixaria muito decepcionado. Por um lado, você tem que segurar a mão para realmente ler arquivos (com gc / get-content). Por outro lado, o indicador de diferença está à direita, longe do conteúdo - é um pesadelo de legibilidade.

A solução para quem procura uma saída sã é

  1. obter um diff real (por exemplo, do GnuWin32)
  2. editar% USERPROFILE% \ Documents \ WindowsPowerShell \ Microsoft.PowerShell_profile.ps1
  3. adicione a linha

    remove-item alias:diff -force

O argumento -force é necessário porque o Powershell é bastante precioso sobre esse alias embutido específico. Se alguém estiver interessado, com o GnuWin32 instalado, também incluo o seguinte no meu perfil do PowerShell:

remove-item alias:rm
remove-item alias:mv
remove-item alias:cp

Principalmente porque o Powershell não entende os argumentos que são executados juntos e digitando, por exemplo "rm -Force -Recurse" é muito mais esforço do que "rm -rf".

O Powershell possui alguns recursos interessantes, mas há algumas coisas que ele simplesmente não deve tentar fazer por mim.

daf
fonte
2

O WinMerge é outra boa ferramenta diff baseada em GUI.

Andy White
fonte
1
Foi assim que eu fiz no passado, que é um processo manual, que eu queria substituir por um pequeno script.
Bratch
1

Há também o Windiff, que fornece uma interface de interface gráfica do usuário (ótima para uso com programas CVS / SVN baseados em GUI)

saschabeaumont
fonte
1

fc.exeé melhor para comparação de texto, pois ele foi projetado para funcionar como * nix diff, ou seja, compara linhas sequencialmente, mostrando as diferenças reais e tentando sincronizar novamente (se as seções diferentes tiverem comprimentos diferentes). Ele também possui algumas opções de controle úteis (texto / binário, distinção entre maiúsculas e minúsculas, números de linhas, comprimento de ressincronização, tamanho do buffer incompatível) e fornece status de saída (-1 sintaxe incorreta, 0 arquivos iguais, 1 arquivo diferente, 1 arquivo diferente e 2 arquivos ausentes). Sendo um utilitário (muito) antigo do DOS, ele tem algumas limitações. Mais notavelmente, ele não funciona automaticamente com Unicode, tratando os 0 MSB de caracteres ASCII como um terminador de linha, para que o arquivo se torne uma sequência de 1 linha de caracteres (@kennycoc: use a opção / U para especificar AMBOS os arquivos são Unicode, WinXP em diante ) e também possui um tamanho de buffer de linha direta de 128 caracteres (128 bytes ASCII,

compare-object foi desenvolvido para determinar se 2 objetos são idênticos em termos de membros. se os objetos são coleções, eles são tratados como SETS (consulte a ajuda de comparação de objetos), ou seja, coleções não ordenadas sem duplicatas. 2 conjuntos são iguais se tiverem os mesmos itens de membro, independentemente de pedido ou duplicação. Isso limita severamente sua utilidade na comparação de arquivos de texto quanto a diferenças. Primeiramente, o comportamento padrão coleta as diferenças até que todo o objeto (file = array of strings) tenha sido verificado, perdendo as informações sobre a posição das diferenças e obscurecendo quais diferenças estão emparelhadas (e não existe um conceito de número de linha para um SET de cordas). O uso de -synchwindow 0 fará com que as diferenças sejam emitidas à medida que ocorrem, mas impede a tentativa de sincronizar novamente. Se um arquivo tiver uma linha extra, as comparações de linha subsequentes poderão falhar, mesmo que os arquivos sejam idênticos (até que exista uma compensação linha extra no outro arquivo realinhando as linhas correspondentes). No entanto, o PowerShell é extremamente versátil e uma comparação útil de arquivos pode ser feita utilizando essa funcionalidade, embora ao custo de uma complexidade substancial e com algumas restrições sobre o conteúdo dos arquivos. Se você precisar comparar arquivos de texto com linhas longas (> 127 caracteres) e onde as linhas correspondem principalmente a 1:

diff (gc file1 | % -begin { $ln1=0 } -process { '{0,6}<<:{1}' -f ++$ln1,$_ }) (gc file2 | % -begin { $ln2=0 } -process { '{0,6}>>:{1}' -f ++$ln2,$_ }) -property { $_.substring(9) } -passthru | sort | out-string -width xx

onde xx é o comprimento da linha mais longa + 9

Explicação

  • (gc file | % -begin { $ln=0 } -process { '{0,6}<<:{1}' -f ++$ln,$_ }) obtém o conteúdo do arquivo e anexa o número da linha e o indicador do arquivo (<< ou >>) a cada linha (usando o operador de cadeia de formatação) antes de passá-lo para diff.
  • -property { $_.substring(9) }diz ao diff para comparar cada par de objetos (strings) ignorando os 9 primeiros caracteres (que são o número da linha e o indicador de arquivo). Isso utiliza a capacidade de especificar uma propriedade calculada (o valor de um bloco de script) em vez do nome de uma propriedade.
  • -passthru faz com que diff produza os diferentes objetos de entrada (que incluem o número da linha e o indicador de arquivo) em vez dos diferentes objetos comparados (que não).
  • sort-objectdepois coloca todas as linhas de volta em seqüência.
    out-string interrompe o truncamento padrão da saída para caber na largura da tela (conforme observado por Marc Towersap) especificando uma largura grande o suficiente para evitar o truncamento. Normalmente, essa saída é colocada em um arquivo que é visualizado usando um editor de rolagem (por exemplo, o bloco de notas).

Nota

O formato do número da linha {0,6} fornece um número de linha com 6 caracteres, justificado à direita e preenchido com espaço (para classificação). Se os arquivos tiverem mais de 999.999 linhas, basta alterar o formato para ser maior. Isso também requer a alteração do $_.substringparâmetro (3 a mais que a largura do número da linha) e o valor xx da cadeia de caracteres (comprimento máximo da linha + $_.substringparâmetro).

codemaster bob
fonte