¿Cómo difiero dos archivos de texto en Windows Powershell?

96

Tengo dos archivos de texto y quiero encontrar las diferencias entre ellos usando Windows Powershell. ¿Hay algo similar a la herramienta Unix diff disponible? ¿O hay otra forma que no he considerado?

Intenté comparar objetos, pero obtuve esta salida críptica:

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

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

Respuestas:

101

Lo descubrí yo mismo. Debido a que Powershell funciona con objetos .net en lugar de texto, debe usar get-content para exponer el contenido de los archivos de texto. Entonces, para realizar lo que estaba tratando de hacer en la pregunta, use:

compare-object (get-content one.txt) (get-content two.txt)
Brian Willis
fuente
1
Me sorprendió mucho cuando intenté comparar dos archivos: una matriz de números sin clasificar y la misma matriz de números después de ordenarlos. No hay salida a pesar de que los archivos son muy diferentes. Aparentemente, comparar objeto no considera el orden.
cgmb
1
@cgmb: creo que puede -SyncWindow 0solucionarlo, aunque no estoy seguro si se ha introducido recientemente. Sin embargo, no es particularmente inteligente al respecto.
James Ruskin
32

Una forma más sencilla de hacerlo es escribir:

diff (cat file1) (cat file2)
Alex Y.
fuente
16
Diff y cat son solo alias para Compare-Object y Get-Content en PowerShell. Es la misma cosa.
Shawn Melton
44
a pesar de ser la respuesta aceptada, me gusta más usar esta sintaxis
Elijah W. Gagne el
Tenga en cuenta que no se comporta como * nix diffen absoluto, como lo señalan otras respuestas aquí. Y cuando utilicé una expresión más compleja en lugar de cat, obtuve un resultado incorrecto, por lo que me uniré a los demás en la recomendación para evitar hacer esto en PowerShell si vienes de * nix.
Nickolay
29

O puede usar el fccomando DOS de esta manera (Esto muestra el resultado de ambos archivos, por lo que tendrá que buscar las diferencias):

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

fces un alias para el cmdlet Format-Custom, así que asegúrese de ingresar el comando comofc.exe . Tenga en cuenta que muchas utilidades de DOS no manejan la codificación UTF-8.

También puede generar un proceso CMD y ejecutarlo fc.

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

Esto le indica a PowerShell que inicie un proceso con el programa 'cmd' usando los parámetros entre comillas. En las comillas, es la opción cmd '/ c' para ejecutar el comando y finalizar. El comando real que debe ejecutar cmd en el proceso es fc filea.txt fileb.txtredirigir la salida al archivo diff.txt.

Puede usar el DOS fc.exedesde powershell.

phord350
fuente
2
+1 para sacar el DOS ^ _ ^
Jeff Bridgman
1
"fc" no funcionaba para mí y no me di cuenta de que tenía que especificarlo como "fc.exe" para diferenciarlo de Format-Custom. Exactamente lo que estaba buscando. Gracias.
Xonatron
Tal vez soy un completo filisteo, pero esto me parece mucho más útil. Resolvió mi problema muy bien.
AJ.
El único problema es que ODIA unicode.
iCodeSometime
7

diff on * nix no es parte del shell, sino una aplicación separada.

¿Hay alguna razón por la que no pueda usar diff.exe en PowerShell?

Puede descargar una versión del paquete UnxUtils ( http://unxutils.sourceforge.net/ )

Mikeage
fuente
10
Debido a que PowerShell está incluido ahora, no hay nada que descargar e instalar.
Bratch
Acabo de usar git diff, porque ya lo tenía instalado. Ni fc.exeproduje Compare-Objectla salida que esperaba.
Raziel
4

compare-object (también conocido como diff alias) es patético si espera que se comporte como un unix diff. Probé el diff (gc file1) (gc file2), y si una línea es demasiado larga, no puedo ver el diff real y, lo que es más importante, no puedo decir en qué número de línea está el diff.

Cuando trato de agregar -passthru, ahora puedo ver la diferencia, pero pierdo en qué archivo está la diferencia y aún no obtengo un número de línea.

Mi consejo, no use powershell para encontrar diferencias en los archivos. Como alguien más notó, fc funciona, y funciona un poco mejor que compare-object, y aún mejor es descargar y usar herramientas reales como el emulador de Unix que mencionó Mikeage.

Marc Towersap
fuente
También parece hacer una comparación de conjuntos (es decir, ignorar el orden) como -SyncWindowmaxint por defecto. Establecer eso en 0 tampoco lo hace funcionar como diff... Y cuando pasé una tubería (... | select-object ...)como entrada, simplemente imprimió tonterías, así que me di por vencido.
Nickolay
3

Como otros han señalado, si esperaba una salida unix-y diff, el uso del alias powershell diff lo decepcionaría mucho. Por un lado, debe tener la mano en la lectura de archivos (con gc / get-content). Por otro lado, el indicador de diferencia está a la derecha, lejos del contenido: es una pesadilla de legibilidad.

La solución para cualquiera que busque una salida sensata es

  1. obtener una diferencia real (por ejemplo, de GnuWin32)
  2. edit% USERPROFILE% \ Documents \ WindowsPowerShell \ Microsoft.PowerShell_profile.ps1
  3. agrega la línea

    remove-item alias:diff -force

Se requiere el argumento -force porque Powershell es bastante valioso sobre este alias incorporado en particular. Si alguien está interesado y tiene instalado GnuWin32, también incluyo lo siguiente en mi perfil de PowerShell:

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

Principalmente porque Powershell no entiende los argumentos que se ejecutan juntos y escribir, por ejemplo "rm -Force -Recurse" es mucho más esfuerzo que "rm -rf".

Powershell tiene algunas características agradables, pero hay algunas cosas que simplemente no debería intentar hacer por mí.

daf
fuente
2

WinMerge es otra buena herramienta de diferencias basada en GUI.

Andy White
fuente
1
Así es como lo hice en el pasado, que es un proceso manual, que quería reemplazar con un pequeño script.
Bratch
1

También está Windiff, que proporciona una interfaz GUI diff (ideal para usar con programas CVS / SVN basados ​​en GUI)

Saschabeaumont
fuente
1

fc.exees mejor para la comparación de texto, ya que está diseñado para funcionar como * nix diff, es decir, compara líneas secuencialmente, muestra las diferencias reales y trata de volver a sincronizar (si las secciones diferentes tienen longitudes diferentes). También tiene algunas opciones de control útiles (texto / binario, mayúsculas y minúsculas, números de línea, longitud de resincronización, tamaño de búfer no coincidente) y proporciona el estado de salida (-1 sintaxis incorrecta, 0 archivos iguales, 1 archivo diferente, faltan 2 archivos). Al ser una (muy) antigua utilidad de DOS, tiene algunas limitaciones. En particular, no funciona automáticamente con Unicode, tratando el 0 MSB de caracteres ASCII como un terminador de línea, por lo que el archivo se convierte en una secuencia de líneas de 1 carácter (@kennycoc: use la opción / U para especificar AMBOS archivos son Unicode, WinXP en adelante ) y también tiene un tamaño de búfer de línea dura de 128 caracteres (128 bytes ASCII,

compare-object está diseñado para determinar si 2 objetos son idénticos en cuanto a miembros. si los objetos son colecciones, entonces se tratan como SETS (consulte la ayuda para comparar objetos), es decir, colecciones SIN ORDENAR sin duplicados. 2 conjuntos son iguales si tienen los mismos elementos miembros independientemente del orden o las duplicaciones. Esto limita severamente su utilidad para comparar archivos de texto en busca de diferencias. En primer lugar, el comportamiento predeterminado recopila las diferencias hasta que se haya verificado todo el objeto (archivo = matriz de cadenas), perdiendo así la información sobre la posición de las diferencias y ocultando qué diferencias están emparejadas (y no hay un concepto de número de línea para un SET de cuerdas). El uso de -synchwindow 0 hará que se emitan las diferencias a medida que ocurren, pero evita que intente volver a sincronizarse, por lo que si un archivo tiene una línea adicional, las comparaciones de líneas posteriores pueden fallar aunque los archivos sean idénticos (hasta que haya un compensatorio línea adicional en el otro archivo, realineando las líneas coincidentes). Sin embargo, powershell es extremadamente versátil y se puede realizar una comparación de archivos útil utilizando esta funcionalidad, aunque a costa de una complejidad sustancial y con algunas restricciones sobre el contenido de los archivos. Si necesita comparar archivos de texto con líneas largas (> 127 caracteres) y donde las líneas coinciden principalmente con 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

donde xx es la longitud de la línea más larga + 9

Explicación

  • (gc file | % -begin { $ln=0 } -process { '{0,6}<<:{1}' -f ++$ln,$_ }) obtiene el contenido del archivo y antepone el número de línea y el indicador de archivo (<< o >>) a cada línea (usando el operador de cadena de formato) antes de pasarlo a diff.
  • -property { $_.substring(9) }le dice a diff que compare cada par de objetos (cadenas) ignorando los primeros 9 caracteres (que son el número de línea y el indicador de archivo). Esto utiliza la capacidad de especificar una propiedad calculada (el valor de un bloque de script) en lugar del nombre de una propiedad.
  • -passthru hace que diff muestre los diferentes objetos de entrada (que incluyen el número de línea y el indicador de archivo) en lugar de los diferentes objetos comparados (que no lo hacen).
  • sort-objectluego vuelve a poner todas las líneas en secuencia.
    out-string detiene el truncamiento predeterminado de la salida para que se ajuste al ancho de la pantalla (como señaló Marc Towersap) al especificar un ancho lo suficientemente grande como para evitar el truncamiento. Normalmente, esta salida se colocaría en un archivo que luego se verá utilizando un editor de desplazamiento (por ejemplo, el bloc de notas).

Nota

El formato de número de línea {0,6} proporciona un número de línea de 6 caracteres justificado a la derecha y con espacio (para ordenar). Si los archivos tienen más de 999,999 líneas, simplemente cambie el formato para que sea más ancho. Esto también requiere alterar el $_.substringparámetro (3 más que el ancho del número de línea) y el valor xx de la cadena (longitud máxima de línea + $_.substringparámetro).

codemaster bob
fuente