180 votes

Comment différencier deux fichiers texte dans Windows Powershell ?

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 diff d'Unix ? Ou existe-t-il un autre moyen auquel je n'ai pas pensé ?

J'ai essayé de comparer les objets, mais j'obtiens ce résultat cryptique :

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

InputObject                                                 SideIndicator
-----------                                                 -------------
two.txt                                                     =>
one.txt                                                     <=

7voto

codemaster bob Points 21

fc.exe est meilleur pour la comparaison de texte car il est conçu pour fonctionner comme *nix diff, c'est-à-dire qu'il compare les lignes séquentiellement, en montrant les différences réelles et en essayant de resynchroniser (si les sections différentes ont des longueurs différentes). Il a aussi quelques options de contrôle utiles (texte/binaire, sensibilité à la casse, numéros de ligne, longueur de resynchronisation, taille du tampon de mismatch) et fournit un statut de sortie (-1 mauvaise syntaxe, 0 fichiers identiques, 1 fichiers différents, 2 fichiers manquants). Étant un (très) vieil utilitaire DOS, il a quelques limitations. Notamment, il ne fonctionne pas automatiquement avec Unicode, traitant le 0 MSB des caractères ASCII comme un terminateur de ligne de sorte que le fichier devient une séquence de lignes de 1 caractère (@kennycoc : utilisez l'option /U pour spécifier que LES DEUX fichiers sont Unicode, à partir de WinXP) et il a également une taille de tampon de ligne dure de 128 caractères (128 octets ASCII, 256 octets Unicode) de sorte que les longues lignes sont divisées et comparées séparément.

compare-object est conçu pour déterminer si 2 objets sont identiques du point de vue de leurs membres. Si les objets sont des collections, ils sont traités comme des SETS (voir l'aide compare-object), c'est-à-dire des collections NON ORDONNÉES sans doublons. Deux ensembles sont égaux s'ils ont les mêmes éléments membres sans tenir compte de l'ordre ou des doublons. Ceci limite sévèrement son utilité pour la comparaison de fichiers texte pour les différences. Premièrement, le comportement par défaut collecte les différences jusqu'à ce que l'objet entier (fichier = tableau de chaînes de caractères) ait été vérifié, perdant ainsi l'information concernant la position des différences et obscurcissant les différences qui sont appariées (et il n'y a pas de concept de numéro de ligne pour un SET de chaînes de caractères). L'utilisation de -synchwindow 0 entraîne l'émission des différences au fur et à mesure qu'elles se produisent, mais l'empêche d'essayer de se resynchroniser. Ainsi, si un fichier comporte une ligne supplémentaire, les comparaisons de lignes suivantes peuvent échouer même si les fichiers sont identiques (jusqu'à ce qu'une ligne supplémentaire compensatoire soit ajoutée dans l'autre fichier, réalignant ainsi les lignes correspondantes). Cependant, powershell est extrêmement polyvalent et une comparaison de fichiers utile peut être effectuée en utilisant cette fonctionnalité, bien qu'au prix d'une complexité substantielle et avec certaines restrictions sur le contenu des fichiers. Si vous avez besoin de comparer des fichiers texte avec de longues lignes (> 127 caractères) et où les lignes correspondent pour la plupart 1:1 (quelques changements de lignes entre les fichiers mais pas de doublons dans un fichier, comme une liste textuelle d'enregistrements de base de données ayant un champ clé), alors en ajoutant des informations à chaque ligne indiquant dans quel fichier elle se trouve, sa position dans ce fichier, puis en ignorant les informations ajoutées pendant la comparaison (mais en les incluant dans la sortie), vous pouvez obtenir une sortie de type *nix diff comme suit (abréviations des alias utilisées) :

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 ligne la plus longue + 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 (en utilisant l'opérateur chaîne de format) avant de le transmettre à diff.
  • -property { $_.substring(9) } dit à diff de comparer chaque paire d'objets (chaînes de caractères) en ignorant les 9 premiers caractères (qui sont le numéro de ligne et l'indicateur de fichier). Ceci utilise la possibilité de spécifier une propriété calculée (la valeur d'un bloc script) au lieu du nom d'une propriété.
  • -passthru permet à diff de sortir les différents objets d'entrée (qui incluent le numéro de ligne et l'indicateur de fichier) au lieu des différents objets comparés (qui ne le font pas).
  • sort-object puis remet toutes les lignes dans l'ordre.
    out-string arrête la troncature par défaut de la sortie pour s'adapter à la largeur de l'écran (comme noté par Marc Towersap) en spécifiant une largeur suffisamment grande pour éviter la troncature. Normalement, cette sortie devrait être placée dans un fichier qui est ensuite visualisé en utilisant un éditeur défilant (par exemple le bloc-notes).

Note

Le format de numéro de ligne {0,6} donne un numéro de ligne de 6 caractères justifié à droite, avec un espace (pour le tri). Si les fichiers ont plus de 999 999 lignes, il suffit de modifier le format pour qu'il soit plus large. Cela nécessite également de modifier le paramètre $_.substring (3 de plus que la largeur du numéro de ligne) et la valeur xx de la chaîne de sortie (longueur maximale de la ligne + $_.substring paramètre).

0 votes

La longue solution donnée par M. Shunz est élégamment conçue pour un résultat agréable à lire. Néanmoins, elle a un problème inhérent : Elle ne renvoie pas les déplacements de lignes (comme un couple de lignes permutées). Par exemple, si le fichier 1 contient les lignes 1, 2 et 3, et que le fichier 2 contient les lignes 1, 3 et 2, aucune différence ne sera signalée.

3voto

Jeshizaemon Points 171

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

1 votes

C'est la façon dont je le faisais dans le passé, qui est un processus manuel, que je voulais remplacer par un petit script.

3voto

daf Points 131

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

La solution pour quiconque cherche une sortie saine est la suivante

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

    remove-item alias:diff -force

L'argument -force est nécessaire parce que Powershell est très attaché à cet alias intégré particulier. Si quelqu'un est intéressé, ayant GnuWin32 installé, j'inclus également ce qui suit 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 exécutés ensemble et que taper, par exemple, "rm -Force -Recurse" demande beaucoup plus d'efforts que "rm -rf".

Powershell a des fonctionnalités intéressantes, mais il y a des choses qu'il ne devrait pas essayer de faire pour moi.

0voto

saschabeaumont Points 2794

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

1 votes

Mais la question était spécifiquement : Comment puis-je différencier deux fichiers texte ? dans Windows Powershell

-1voto

Josiah DeWitt Points 129

Powershell est au mieux maladroit et un triste remplacement de diff -y. Je suis venu ici pour chercher comment cela pouvait fonctionner, j'ai fini par ouvrir les fichiers dans notepad++. Exactement ce dont j'avais besoin

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X