如何在Windows Powershell中区分两个文本文件?


96

我有两个文本文件,想要使用Windows Powershell查找它们之间的差异。是否有类似于Unix diff工具的工具?还是我没有考虑过其他方法?

我尝试了compare-object,但是得到了这个神秘的输出:

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

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

Answers:


101

我自己想通了。由于Powershell使用的是.net对象而不是文本,因此您需要使用get-content公开文本文件的内容。因此,要执行我在问题中试图做的事情,请使用:

compare-object (get-content one.txt) (get-content two.txt)

1
当我尝试比较两个文件时,我感到非常惊讶:一个未排序的数字数组,以及对它们进行排序后的相同数字数组。尽管文件非常不同,但是没有输出。显然,比较对象不考虑顺序。
cgmb

1
@cgmb- -SyncWindow 0我相信,您可以使用它来解决此问题,尽管我不确定它是否只是最近才引入的。不过,这并不是特别聪明。
James Ruskin

32

一种更简单的方法是编写:

diff (cat file1) (cat file2)

15
Diff和cat只是PowerShell中Compare-Object和Get-Content的别名。是同一回事。
肖恩·梅尔顿

4
尽管这与接受的答案相同,但我更喜欢使用这种语法
Elijah W. Gagne

请注意,它的行为根本不像* nix diff,正如这里的其他答案所述。当我使用更复杂的表达式代替cat错误输出时,因此如果您来自* nix,我将与其他建议一起加入以避免在PowerShell中执行此操作。
Nickolay

29

或者,您可以fc像这样使用DOS 命令(这显示了两个文件的输出,因此您必须扫描差异):

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

fc是Format-Custom cmdlet的别名,因此请确保将命令输入为fc.exe。请注意,许多DOS实用程序不处理UTF-8编码。

您还可以生成CMD进程并fc在其中运行。

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

这指示PowerShell使用引号中的参数使用“ cmd”程序启动进程。用引号引起来的是'/ c'cmd选项,用于运行命令并终止。cmd在此过程中运行的实际命令是fc filea.txt fileb.txt将输出重定向到文件diff.txt

您可以fc.exe在powershell中使用DOS 。


2
+1以显示DOS ^ _ ^
Jeff Bridgman

1
“ fc”不适用于我,并且我没有意识到我必须将其指定为“ fc.exe”以区别于Format-Custom。正是我想要的。谢谢。
Xonatron

也许我是一个完整的非利士人,但这对我来说似乎更有用。它很好地解决了我的问题。
AJ。

唯一的问题是它破坏了Unicode。
iCodeSometime

7

* nix上的差异不是外壳程序的一部分,而是单独的应用程序。

有什么原因不能只在PowerShell下使用diff.exe?

您可以从UnxUtils包(http://unxutils.sourceforge.net/)下载版本。


10
由于现在包括PowerShell,因此无需下载和安装任何内容。
2012年

我刚刚结束使用git diff,因为我已经安装了它。既不fc.exe也不Compare-Object产生我期望的输出。
拉齐尔

4

如果您希望比较对象(例如diff别名)表现得像Unix diff一样,那是可悲的。我尝试了diff(gc file1)(gc file2),如果一行太长,我看不到实际的diff,更重要的是,我无法确定diff所在的行号。

当我尝试添加-passthru时,现在可以看到区别,但是我丢失了区别所在的文件,但仍然没有获得行号。

我的建议是,不要使用powershell查找文件中的差异。正如其他人指出的那样,fc可以工作,并且比比较对象要好一些,甚至更好的是下载和使用Mikeage提到的诸如unix模拟器的真实工具。


-SyncWindow默认情况下,maxint 似乎也进行了集合比较(即忽略顺序)。将其设置为0并不会使其工作diff……当我通过管道(... | select-object ...)作为输入时,它只是打印废话,所以我放弃了。
Nickolay

3

正如其他人指出的那样,如果您期望使用unix-y diff输出,那么使用powershell diff别名会让您失望。一方面,您必须握住它来实际读取文件(使用gc / get-content)。另一方面,差异指示器位于右侧,距离内容很远-这是可读性的噩梦。

对于任何寻求合理输出的解决方案是

  1. 得到一个真正的差异(例如从GnuWin32)
  2. 编辑%USERPROFILE%\ Documents \ WindowsPowerShell \ Microsoft.PowerShell_profile.ps1
  3. 添加线

    remove-item alias:diff -force

-force参数是必需的,因为Powershell对于此特定的内置别名非常宝贵。如果有人感兴趣,安装了GnuWin32,我还将在powershell配置文件中添加以下内容:

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

主要是因为Powershell无法理解同时运行并键入的参数,例如,“ rm -Force -Recurse”比“ rm -rf”需要更多的精力。

Powershell具有一些不错的功能,但是有些事情它不应该为我做。




1

fc.exe比较适合于文本比较,因为它的设计类似于* nix diff,即按顺序比较行,显示实际差异并尝试重新同步(如果不同部分的长度不同)。它还具有一些有用的控制选项(文本/二进制,区分大小写,行号,重新同步长度,不匹配的缓冲区大小),并提供退出状态(-1错误的语法,0个相同的文件,1个不同的文件,2个丢失的文件)。作为(非常)旧的DOS实用程序,它确实有一些限制。最值得注意的是,它不能自动与Unicode一起使用,将0个ASCII字符的MSB作为行终止符,因此文件变成1个字符行的序列(@kennycoc:使用/ U选项指定两个文件均为Unicode,从WinXP开始),并且硬线缓冲区大小为128个字符(128个字节的ASCII,

compare-object用于确定2个对象在成员方面是否相同。如果对象是集合,则将它们视为SETS(请参阅帮助比较对象),即无重复的UNORDERED集合。如果成员项相同,则无论顺序或重复项如何,两组都相等。这严重限制了它在比较文本文件是否有差异方面的有用性。首先,默认行为会收集差异,直到检查了整个对象(文件=字符串数组),从而丢失了有关差异位置的信息,并模糊了配对的差异(并且SET中没有行号的概念)的字符串)。使用-synchwindow 0会导致差异出现时发出,但是会阻止差异尝试重新同步,因此,如果一个文件有多余的行,那么即使这些文件是相同的,后续的行比较也可能失败(直到有补偿)其他文件中的多余行,从而重新对齐匹配的行)。但是,powershell具有极强的通用性,并且可以通过利用此功能来完成有用的文件比较,尽管这样做的代价是相当复杂,并且对文件内容有一些限制。如果您需要比较文本行较长(> 127个字符)并且文本行大部分匹配的文本文件,请执行以下操作:

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

其中xx是最长线的长度+ 9

说明

  • (gc file | % -begin { $ln=0 } -process { '{0,6}<<:{1}' -f ++$ln,$_ }) 获取文件的内容,并将行号和文件指示符(<<或>>)添加到每一行(使用格式字符串运算符),然后再将其传递给diff。
  • -property { $_.substring(9) }告诉diff比较每对对象(字符串),而忽略前9个字符(即行号和文件指示符)。这利用了指定计算的属性(脚本块的值)而不是属性名称的能力。
  • -passthru 使diff输出不同的输入对象(包括行号和文件指示符),而不是不同的比较对象(不包括)。
  • sort-object然后将所有行放回序列中。
    out-string通过指定足以避免截断的宽度来停止输出的默认截断以适合屏幕宽度(如Marc Towersap所述)。通常,此输出将放入一个文件中,然后使用滚动编辑器(例如记事本)进行查看。

注意

行号格式{0,6}给出一个右对齐的空格填充6个字符的行号(用于排序)。如果文件的行数超过999,999,则只需将格式更改为更宽即可。这还需要更改$_.substring参数(比行号宽度多3)和字符串xx值(最大行长+ $_.substring参数)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.