Comment puis-je comparer deux fichiers texte dans Windows Powershell?

96

J'ai deux fichiers texte et je veux trouver les différences entre eux en utilisant Windows Powershell. Existe-t-il quelque chose de similaire à l'outil de diff Unix? Ou y a-t-il un autre moyen que je n'ai pas envisagé?

J'ai essayé compare-object, mais obtenez cette sortie cryptée:

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

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

Réponses:

101

Je l'ai compris moi-même. Etant donné que Powershell fonctionne avec des objets .net plutôt que du texte, vous devez utiliser get-content pour exposer le contenu des fichiers texte. Donc, pour exécuter ce que j'essayais de faire dans la question, utilisez:

compare-object (get-content one.txt) (get-content two.txt)
Brian Willis
la source
1
J'ai été très surpris lorsque j'ai essayé de comparer deux fichiers: un tableau de nombres non trié et le même tableau de nombres après leur tri. Il n'y a pas de sortie malgré le fait que les fichiers soient très différents. Apparemment, l'objet de comparaison ne considère pas l'ordre.
cgmb
1
@ cgmb - -SyncWindow 0Je pense que vous pouvez utiliser ce problème pour résoudre ce problème, même si je ne suis pas sûr qu'il ait été introduit récemment. Ce n'est pas particulièrement intelligent à ce sujet, cependant.
James Ruskin
32

Une façon plus simple de le faire est d’écrire:

diff (cat file1) (cat file2)
Alex Y.
la source
16
Diff et cat ne sont que des alias pour Compare-Object et Get-Content dans PowerShell. C'est la même chose.
Shawn Melton
4
Bien que cela soit la même chose que la réponse acceptée, j'aime mieux utiliser cette syntaxe
Elijah W. Gagne
Notez qu'il ne se comporte pas du tout comme * nix diff, comme d'autres réponses le notent ici. Et lorsque j'ai utilisé une expression plus complexe à la place de la catsortie incorrecte, je me joins donc aux autres recommandations pour éviter de le faire dans PowerShell si vous venez de * nix.
Nickolay le
29

Ou vous pouvez utiliser la fccommande DOS comme suit (ceci affiche la sortie des deux fichiers, vous devrez donc rechercher les différences):

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

fcest un alias pour l'applet de commande Format-Custom, assurez-vous d'entrer la commande en tant quefc.exe . Veuillez noter que de nombreux utilitaires DOS ne gèrent pas le codage UTF-8.

Vous pouvez également créer un processus CMD et l'exécuter fc.

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

Cela indique à PowerShell de démarrer un processus avec le programme 'cmd' en utilisant les paramètres entre guillemets. Dans les guillemets, c’est l’option '/ c' cmd pour exécuter la commande et se terminer. La commande réelle à exécuter par cmd dans le processus fc filea.txt fileb.txtredirige la sortie vers le fichier diff.txt.

Vous pouvez utiliser le DOS fc.exedepuis PowerShell.

phord350
la source
2
+1 pour sortir le DOS ^ _ ^
Jeff Bridgman
1
"fc" ne fonctionnait pas pour moi et je ne savais pas que je devais le spécifier en tant que "fc.exe" pour le différencier de Format-Custom. Exactement ce que je cherchais. Merci.
Xonatron
Je suis peut-être un philistin complet, mais cela me semble beaucoup plus utilisable. Cela a très bien résolu mon problème.
AJ.
Le seul problème est qu'il déteste unicode.
iCodeSometime
7

diff on * nix ne fait pas partie du shell, mais est une application distincte.

Y a-t-il une raison pour laquelle vous ne pouvez pas utiliser simplement diff.exe sous PowerShell?

Vous pouvez télécharger une version à partir du package UnxUtils ( http://unxutils.sourceforge.net/ )

Mikeage
la source
10
Puisque PowerShell est inclus maintenant, rien à télécharger et à installer.
Bratch
Je viens d'utiliser git diff, parce que je l'avais déjà installé. Ni fc.exeni Compare-Objectproduit la sortie que je m'attendais.
Raziel
4

compare-object (alias diff alias) est pathétique si vous vous attendez à ce qu'il se comporte comme un diff unix. J'ai essayé le diff (gc file1) (gc file2), et si une ligne est trop longue, je ne peux pas voir le diff réel et, plus important encore, je ne peux pas dire sur quel numéro de ligne le diff est affiché.

Lorsque j'essaie d'ajouter -passthru, je peux maintenant voir la différence, mais je perds le fichier dans lequel se trouve la différence et je ne reçois toujours pas de numéro de ligne.

Mon conseil, n'utilisez pas Powershell pour trouver des différences dans les fichiers. Comme quelqu'un l'a noté, fc fonctionne, et fonctionne un peu mieux que compare-object, et même le téléchargement et l'utilisation d'outils réels, tels que l'émulateur Unix mentionné par Mikeage, sont encore meilleurs.

Marc Towersap
la source
Il semble également faire une comparaison d'ensemble (c'est-à-dire en ignorant l'ordre) comme -SyncWindowmaxint par défaut. Définir ce paramètre sur 0 ne le fait pas fonctionner de la même diffmanière ... Et lorsque je passais un tuyau (... | select-object ...)en entrée, cela imprimait un non-sens, alors j'ai abandonné.
Nickolay le
3

Comme d'autres l'ont fait remarquer, si vous attendiez une sortie diff unix-y, utiliser le diff alias powershell vous laisserait tomber. D'une part, vous devez tenir la main pour lire les fichiers (avec gc / get-content). D'autre part, l'indicateur de différence est à droite, loin du contenu - c'est un cauchemar de lisibilité.

La solution pour ceux qui recherchent une sortie saine est

  1. obtenir un vrai diff (par exemple de GnuWin32)
  2. modifier% USERPROFILE% \ Documents \ WindowsPowerShell \ Microsoft.PowerShell_profile.ps1
  3. ajouter la ligne

    remove-item alias:diff -force

L'argument -force est requis car Powershell est très précieux à propos de cet alias incorporé particulier. Si quelqu'un est intéressé par l'installation de GnuWin32, j'inclus également les éléments suivants dans mon profil powershell:

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

Principalement parce que Powershell ne comprend pas les arguments qui sont combinés et dactylographiés, par exemple, "rm -Force -Recurse" nécessite beaucoup plus d'efforts que "rm -rf".

Powershell a quelques fonctionnalités intéressantes, mais il y a certaines choses qu'il ne faut tout simplement pas essayer de faire pour moi.

daf
la source
2

WinMerge est un autre bon outil de différenciation basé sur une interface graphique.

Andy White
la source
1
C’est ce que j’ai fait par le passé, c’est-à-dire un processus manuel, que je voulais remplacer par un petit script.
Bratch
1

Il y a aussi Windiff qui fournit une interface graphique GUI (idéal pour une utilisation avec les programmes CVS / SVN basés sur une interface graphique)

Saschabeaumont
la source
1

fc.exeest préférable pour la comparaison de texte car il est conçu pour fonctionner comme * nix diff, c'est-à-dire compare les lignes séquentiellement, en montrant les différences réelles et en essayant de se resynchroniser (si les sections différentes ont des longueurs différentes). Il dispose également de quelques options de contrôle utiles (texte / binaire, respect de la casse, numéros de ligne, longueur de resynchronisation, taille du tampon incohérent) et fournit le statut de sortie (syntaxe -1 incorrecte, 0 fichier identique, 1 fichier différent, 2 fichier manquant). Étant un (très) ancien utilitaire DOS, il a quelques limitations. Plus particulièrement, il ne fonctionne pas automatiquement avec Unicode, il traite le caractère 0 MSB de caractères ASCII comme un séparateur de ligne, de sorte que le fichier devient une séquence de 1 caractère (@kennycoc: utilisez l’option / U pour spécifier que les deux fichiers sont Unicode, WinXP, etc. ) et possède également une taille de tampon de ligne dure de 128 caractères (ASCII 128 octets,

compare-object est conçu pour déterminer si 2 objets sont identiques au niveau des membres. si les objets sont des collections, ils sont traités comme des SETS (voir help compare-object), c'est-à-dire des collections UNORDERED sans doublons. 2 jeux sont égaux s'ils ont les mêmes articles de membre indépendamment de l'ordre ou des duplications. Cela limite considérablement son utilité pour comparer des fichiers texte aux différences. Tout d’abord, le comportement par défaut collecte les différences jusqu’à ce que l’objet entier (fichier = tableau de chaînes) ait été vérifié, perdant ainsi les informations relatives à la position des différences et masquant les différences appariées (et aucune notion de numéro de ligne pour un SET). de chaînes). Si vous utilisez -synchwindow 0, les différences sont émises au fur et à mesure qu'elles se produisent, mais l'empêchent d'essayer de se resynchroniser. Ainsi, si un fichier comporte une ligne supplémentaire, les comparaisons de ligne suivantes peuvent échouer même si les fichiers sont identiques (jusqu'à ce qu'il y ait compensation). ligne supplémentaire dans l’autre fichier, réalignant ainsi les lignes correspondantes). Cependant, powershell est extrêmement polyvalent et une comparaison de fichiers utile peut être réalisée à l'aide de cette fonctionnalité, bien que cela se fasse au prix d'une complexité considérable et de certaines restrictions sur le contenu des fichiers. Si vous devez comparer des fichiers texte comportant de longues lignes (> 127 caractères) et dont les lignes correspondent généralement à 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

où xx est la longueur de la plus longue ligne + 9

Explication

  • (gc file | % -begin { $ln=0 } -process { '{0,6}<<:{1}' -f ++$ln,$_ }) récupère le contenu du fichier et ajoute le numéro de ligne et l'indicateur de fichier (<< ou >>) à chaque ligne (à l'aide de l'opérateur de chaîne de formatage) avant de le transmettre à diff.
  • -property { $_.substring(9) }indique à diff de comparer chaque paire d'objets (chaînes) en ignorant les 9 premiers caractères (qui sont le numéro de ligne et l'indicateur de fichier). Cela utilise la possibilité de spécifier une propriété calculée (la valeur d'un bloc de script) au lieu du nom d'une propriété.
  • -passthru fait en sorte que diff produise les objets d'entrée différents (qui incluent le numéro de ligne et l'indicateur de fichier) au lieu des objets comparés différents (qui ne le font pas).
  • sort-objectpuis remet toutes les lignes en séquence.
    out-string arrête la troncature par défaut de la sortie pour l'adapter à la largeur de l'écran (comme l'a noté Marc Towersap) en spécifiant une largeur suffisamment grande pour éviter la troncature. Normalement, cette sortie serait placée dans un fichier qui est ensuite visualisé à l'aide d'un éditeur de défilement (par exemple, le bloc-notes).

Remarque

Le format de numéro de ligne {0,6} donne un numéro de ligne à 6 caractères, complété par des espaces et assorti d'espaces (pour le tri). Si les fichiers ont plus de 999 999 lignes, changez simplement le format pour qu’il soit plus large. Cela nécessite également de modifier le $_.substringparamètre (3 de plus que la largeur du numéro de ligne) et la valeur de sortie xx (longueur de ligne maximale + $_.substringparamètre).

codemaster bob
la source