Wie kann ich zwei Textdateien in Windows Powershell unterscheiden?

96

Ich habe zwei Textdateien und möchte mit Windows Powershell die Unterschiede zwischen ihnen herausfinden. Gibt es etwas Ähnliches wie das Unix Diff Tool? Oder gibt es einen anderen Weg, den ich nicht in Betracht gezogen habe?

Ich habe Compare-Object ausprobiert, erhalte aber diese kryptische Ausgabe:

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

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

Antworten:

101

Hab es selbst rausgefunden. Da Powershell nicht mit Text, sondern mit .NET-Objekten arbeitet, müssen Sie get-content verwenden, um den Inhalt der Textdateien anzuzeigen. Um also das auszuführen, was ich in der Frage versucht habe, benutze:

compare-object (get-content one.txt) (get-content two.txt)
Brian Willis
quelle
1
Ich war sehr überrascht, als ich versuchte, zwei Dateien zu vergleichen: ein unsortiertes Zahlenfeld und dasselbe Zahlenfeld, nachdem ich sie sortiert hatte. Es erfolgt keine Ausgabe, obwohl die Dateien sehr unterschiedlich sind. Offensichtlich berücksichtigt das Vergleichsobjekt die Reihenfolge nicht.
CGMB
1
@cgmb - -SyncWindow 0Ich glaube, Sie können das beheben, obwohl ich nicht sicher bin, ob es erst kürzlich eingeführt wurde. Es ist jedoch nicht besonders klug.
James Ruskin
32

Eine einfachere Möglichkeit besteht darin, Folgendes zu schreiben:

diff (cat file1) (cat file2)
Alex Y.
quelle
16
Diff und cat sind nur Aliase für Compare-Object und Get-Content in PowerShell. Es ist das selbe Ding.
Shawn Melton
4
Obwohl dies mit der akzeptierten Antwort identisch ist, verwende ich diese Syntax gerne mehr
Elijah W. Gagne,
Beachten Sie, dass es sich überhaupt nicht wie * nix verhält diff, wie andere Antworten hier vermerken. Und als ich einen komplexeren Ausdruck anstelle einer catfalschen Ausgabe verwendet habe, werde ich mich den anderen in der Empfehlung anschließen, dies in PowerShell zu vermeiden, wenn Sie von * nix kommen.
Nickolay
29

Oder Sie können den DOS- fcBefehl wie folgt verwenden (Dies zeigt die Ausgabe beider Dateien an, sodass Sie nach den Unterschieden suchen müssen):

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

fcist ein Alias ​​für das Cmdlet Format-Custom. Geben Sie den Befehl also unbedingt als einfc.exe . Bitte beachten Sie, dass viele DOS-Dienstprogramme die UTF-8-Codierung nicht verarbeiten.

Sie können auch einen CMD-Prozess erzeugen und in ihm ausführen fc.

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

Dies weist PowerShell an, einen Prozess mit dem Programm 'cmd' zu starten, indem die Parameter in Anführungszeichen verwendet werden. In den Anführungszeichen steht die Cmd-Option '/ c', um den Befehl auszuführen und zu beenden. Der eigentliche Befehl, der dabei von cmd ausgeführt wird, ist das fc filea.txt fileb.txtUmleiten der Ausgabe in die Datei diff.txt.

Sie können das DOS fc.exein Powershell verwenden.

phord350
quelle
2
+1 für herausbringen der DOS ^ _ ^
Jeff Bridgman
1
"fc" funktionierte nicht für mich und ich wusste nicht, dass ich es als "fc.exe" angeben musste, um es von Format-Custom zu unterscheiden. Genau das, wonach ich gesucht habe. Vielen Dank.
Xonatron
Vielleicht bin ich ein absoluter Philister, aber das scheint mir viel nützlicher zu sein. Es hat mein Problem sehr gut gelöst.
AJ.
Das einzige Problem ist es hasst Unicode.
iCodeSometime
7

diff on * nix ist nicht Teil der Shell, sondern eine separate Anwendung.

Gibt es einen Grund, warum Sie diff.exe nicht einfach unter PowerShell verwenden können?

Sie können eine Version aus dem UnxUtils-Paket herunterladen ( http://unxutils.sourceforge.net/ ).

Mikeage
quelle
10
Da PowerShell jetzt enthalten ist, müssen Sie nichts herunterladen und installieren.
Bratch
Ich habe gerade verwendet git diff, weil ich es bereits installiert hatte. Weder produziert fc.exenoch Compare-Objectdie Ausgabe, die ich erwartet hatte.
Raziel
4

compare-object (aka diff alias) ist erbärmlich, wenn Sie erwarten, dass es sich wie ein Unix-Diff verhält. Ich habe das Diff (gc file1) (gc file2) ausprobiert, und wenn eine Zeile zu lang ist, kann ich das tatsächliche Diff nicht sehen, und was noch wichtiger ist, ich kann nicht sagen, auf welcher Zeilennummer sich das Diff befindet.

Wenn ich versuche, -passthru hinzuzufügen, sehe ich jetzt den Unterschied, aber ich verliere, in welcher Datei sich der Unterschied befindet, und ich erhalte immer noch keine Zeilennummer.

Mein Rat, verwenden Sie keine Powershell, um Unterschiede in Dateien zu finden. Wie jemand anderes angemerkt hat, funktioniert fc ein bisschen besser als compare-object und noch besser ist es, echte Tools wie den von Mikeage erwähnten Unix-Emulator herunterzuladen und zu verwenden.

Marc Towersap
quelle
Es scheint auch einen festgelegten Vergleich durchzuführen (dh die Reihenfolge zu ignorieren), da -SyncWindowdies standardmäßig maxint ist. diffWenn ich das auf 0 setze, funktioniert es auch nicht so ... Und als ich eine Pipe (... | select-object ...)als Eingabe übergeben habe, hat es nur Unsinn gedruckt, also habe ich aufgegeben.
Nickolay
3

Wie andere angemerkt haben, würde die Verwendung des Powershell-Diff-Alias ​​Sie im Stich lassen, wenn Sie eine Unix-Y-Diff-Ausgabe erwarten würden. Zum einen muss man die Hand beim Lesen von Dateien halten (mit gc / get-content). Zum anderen befindet sich der Differenzindikator rechts, weit entfernt vom Inhalt - es ist ein Albtraum der Lesbarkeit.

Die Lösung für alle, die eine vernünftige Leistung suchen, ist

  1. bekomme ein echtes diff (zB von GnuWin32)
  2. Bearbeiten Sie% USERPROFILE% \ Documents \ WindowsPowerShell \ Microsoft.PowerShell_profile.ps1
  3. füge die Zeile hinzu

    remove-item alias:diff -force

Das Argument -force ist erforderlich, da Powershell bei diesem speziellen eingebauten Alias ​​sehr wertvoll ist. Wenn jemand Interesse hat, GnuWin32 zu installieren, füge ich auch Folgendes in mein Powershell-Profil ein:

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

Hauptsächlich, weil Powershell keine Argumente versteht, die zusammenlaufen und die Eingabe von "rm -Force -Recurse" ist viel mühsamer als "rm -rf".

Powershell hat einige nette Funktionen, aber es gibt einige Dinge, die es einfach nicht versuchen sollte, für mich zu tun.

daf
quelle
2

WinMerge ist ein weiteres gutes GUI-basiertes Diff-Tool.

Andy White
quelle
1
So habe ich es in der Vergangenheit gemacht, was ein manueller Prozess ist, den ich durch ein kleines Skript ersetzen wollte.
Bratch
1

Es gibt auch Windiff , das eine GUI-Diff-Schnittstelle bietet ( ideal für die Verwendung mit GUI-basierten CVS / SVN-Programmen).

saschabeaumont
quelle
1

fc.exeist besser für das Vergleichen von Text, da es so konzipiert ist, dass es wie * nix diff funktioniert, dh Zeilen sequentiell vergleicht, die tatsächlichen Unterschiede anzeigt und versucht, neu zu synchronisieren (wenn die unterschiedlichen Abschnitte unterschiedliche Längen haben). Es verfügt auch über einige nützliche Steuerungsoptionen (Text / Binär, Groß- / Kleinschreibung, Zeilennummern, Resynchronisationslänge, Puffergröße für Nichtübereinstimmung) und bietet einen Beendigungsstatus (-1 ungültige Syntax, 0 gleiche Dateien, 1 unterschiedliche Dateien, 2 fehlende Dateien). Da es sich um ein (sehr) altes DOS-Dienstprogramm handelt, gibt es einige Einschränkungen. Insbesondere funktioniert es nicht automatisch mit Unicode. Das 0-MSB-Zeichen von ASCII-Zeichen wird als Zeilenabschluss behandelt, sodass die Datei zu einer Folge von 1-Zeichen-Zeilen wird (@kennycoc: Verwenden Sie die Option / U, um anzugeben, dass BEIDE Dateien Unicode und WinXP sind ) und es hat auch eine feste Zeilenpuffergröße von 128 Zeichen (128 Bytes ASCII,

compare-object wurde entwickelt, um festzustellen, ob zwei Objekte in Bezug auf die Mitglieder identisch sind. Handelt es sich bei den Objekten um Auflistungen, werden sie als SETS (siehe Hilfe Vergleichsobjekt) behandelt, dh als UNORDERED-Auflistungen ohne Duplikate. 2 Sätze sind gleich, wenn sie unabhängig von der Reihenfolge oder der Vervielfältigung die gleichen Elemente aufweisen. Dies schränkt seine Nützlichkeit zum Vergleichen von Textdateien auf Unterschiede stark ein. Erstens sammelt das Standardverhalten die Unterschiede, bis das gesamte Objekt (Datei = Array von Zeichenfolgen) überprüft wurde, wodurch die Informationen bezüglich der Position der Unterschiede verloren gehen und verdeckt wird, welche Unterschiede gepaart sind (und es gibt kein Konzept der Zeilennummer für ein SET von Streichern). Wenn Sie -synchwindow 0 verwenden, werden die Unterschiede ausgegeben, sobald sie auftreten. Wenn jedoch eine Datei eine zusätzliche Zeile enthält, können nachfolgende Zeilenvergleiche fehlschlagen, obwohl die Dateien ansonsten identisch sind (bis eine Kompensation vorliegt) zusätzliche Zeile in der anderen Datei, wodurch die übereinstimmenden Zeilen neu ausgerichtet werden). Powershell ist jedoch äußerst vielseitig und ein nützlicher Dateivergleich kann mithilfe dieser Funktionalität durchgeführt werden, allerdings auf Kosten einer erheblichen Komplexität und mit einigen Einschränkungen für den Inhalt der Dateien. Wenn Sie Textdateien mit langen (> 127 Zeichen) Zeilen vergleichen müssen und die Zeilen meistens mit 1 übereinstimmen:

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

Dabei ist xx die Länge der längsten Linie + 9

Erläuterung

  • (gc file | % -begin { $ln=0 } -process { '{0,6}<<:{1}' -f ++$ln,$_ }) Ruft den Inhalt der Datei ab und stellt jeder Zeile die Zeilennummer und die Dateianzeige (<< oder >>) voran (unter Verwendung des Format-String-Operators), bevor die Datei an diff übergeben wird.
  • -property { $_.substring(9) }weist diff an, jedes Objektpaar (Strings) zu vergleichen, wobei die ersten 9 Zeichen (Zeilennummer und Dateianzeige) ignoriert werden. Dies nutzt die Möglichkeit, eine berechnete Eigenschaft (den Wert eines Skriptblocks) anstelle des Namens einer Eigenschaft anzugeben.
  • -passthru veranlasst diff, die unterschiedlichen Eingabeobjekte (einschließlich Zeilennummer und Dateianzeige) anstelle der unterschiedlichen verglichenen Objekte (die dies nicht tun) auszugeben.
  • sort-objectDann werden alle Zeilen wieder in die richtige Reihenfolge gebracht.
    out-string stoppt das standardmäßige Abschneiden der Ausgabe, um sie an die Bildschirmbreite anzupassen (wie von Marc Towersap angegeben), indem eine Breite angegeben wird, die groß genug ist, um ein Abschneiden zu vermeiden. Normalerweise wird diese Ausgabe in eine Datei geschrieben, die dann mit einem Bildlauf-Editor (z. B. Editor) angezeigt wird.

Hinweis

Das Zeilennummernformat {0,6} gibt eine rechtsbündige, mit Leerzeichen aufgefüllte 6-stellige Zeilennummer (zum Sortieren) an. Wenn die Dateien mehr als 999.999 Zeilen haben, ändern Sie einfach das Format, um breiter zu werden. Dazu müssen Sie auch den $_.substringParameter (3 mehr als die Zeilennummernbreite) und den Wert xx für die Zeichenfolge ändern (maximale Zeilenlänge + $_.substringParameter).

Codemaster Bob
quelle