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

Bri*_*lis 128 windows powershell

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

我试过比较对象,但得到这个神秘的输出:

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

InputObject                                                 SideIndicator
-----------                                                 -------------
two.txt                                                     =>
one.txt                                                     <=
Run Code Online (Sandbox Code Playgroud)

Bri*_*lis 134

我自己想出来的。因为 Powershell 使用 .net 对象而不是文本,所以您需要使用 get-content 来公开文本文件的内容。因此,要执行我在问题中尝试执行的操作,请使用:

compare-object (get-content one.txt) (get-content two.txt)
Run Code Online (Sandbox Code Playgroud)

  • 当我尝试比较两个文件时,我感到非常惊讶:一个未排序的数字数组,以及排序后的相同数字数组。尽管文件非常不同,但没有输出。显然,比较对象不考虑顺序。 (3认同)
  • @cgmb - 你可以使用 `-SyncWindow 0` 来解决这个问题,我相信,但我不确定它是不是最近才被引入。不过,它并不是特别聪明。 (2认同)
  • 请注意,在比较大文件时,这非常慢。DOS 的 `fc.exe` 或 *nix' `diff` 是更好的选择。 (2认同)

小智 51

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

diff (cat file1) (cat file2)
Run Code Online (Sandbox Code Playgroud)

  • Diff 和 cat 只是 PowerShell 中 Compare-Object 和 Get-Content 的别名。这是同样的事情。 (24认同)
  • 尽管这与接受的答案相同,但我更喜欢使用此语法 (9认同)
  • 请注意,它的行为根本不像 *nix `diff`,正如此处的其他答案所指出的那样。当我使用更复杂的表达式代替 `cat` 时,我得到了不正确的输出,所以如果你来自 *nix,我将在建议中加入其他人以避免在 PowerShell 中这样做。 (3认同)

小智 35

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

fc.exe filea.txt fileb.txt > diff.txt
Run Code Online (Sandbox Code Playgroud)

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

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

start cmd "/c  ""fc filea.txt fileb.txt >diff.txt"""
Run Code Online (Sandbox Code Playgroud)

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

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

  • +1 带出 DOS ^_^ (2认同)

Mik*_*age 8

*nix 上的 diff 不是 shell 的一部分,而是一个单独的应用程序。

有什么理由不能在 PowerShell 下使用 diff.exe 吗?

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

  • 因为现在包含 PowerShell,所以无需下载和安装。 (12认同)

小智 6

如果您希望比较对象(又名 diff 别名)表现得像 unix 差异,则它是可悲的。我尝试了 diff (gc file1) (gc file2),如果一行太长,我看不到实际的 diff,更重要的是,我无法判断 diff 位于哪个行号。

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

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


小智 6

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

Compare-object 旨在确定两个对象是否在成员方面相同。如果对象是集合,那么它们将被视为集合(请参阅帮助比较对象),即无重复的无序集合。如果 2 个集合具有相同的成员项目,则无论顺序或重复如何,它们都是相等的。这严重限制了它比较文本文件差异的有用性。首先,默认行为收集差异,直到检查整个对象(文件 = 字符串数组),从而丢失有关差异位置的信息并模糊哪些差异是配对的(并且 SET 没有行号的概念)的字符串)。使用 -synchwindow 0 将导致差异在发生时被发出,但会阻止它尝试重新同步,因此如果一个文件有多余的行,则后续行比较可能会失败,即使文件在其他方面相同(直到有补偿)另一个文件中的额外行,从而重新对齐匹配行)。然而,powershell 的用途非常广泛,可以通过利用此功能来完成有用的文件比较,尽管代价是相当复杂,并且对文件内容有一些限制。如果您需要比较长行(> 127 个字符)的文本文件,并且这些行大多以 1:1 匹配(文件之间的行有一些变化,但文件内没有重复,例如具有关键字段的数据库记录的文本列表)然后通过向每一行添加信息来指示它在哪个文件中、它在该文件中的位置,然后在比较过程中忽略添加的信息(但将其包含在输出中),您可以获得类似 *nix diff 的输出,如下所示(使用别名缩写) ):

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
Run Code Online (Sandbox Code Playgroud)

其中 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)和out-string xx值(最大行长度+$_.substring参数)。