175

I have two text files and want to find the differences between them using Windows Powershell. Is there something similar to the Unix diff tool available? Or is there another other way I haven't considered?

I've tried compare-object, but got this cryptic output:

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

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

10 Answers 10

181

Figured it out myself. Because Powershell works with .net objects rather than text, you need to use get-content to expose the contents of the text files. So to perform what I was trying to do in the question, use:

compare-object (get-content one.txt) (get-content two.txt)
4
  • 6
    I was very surprised when I tried to compare two files: an unsorted array of numbers, and the same array of numbers after sorting them. There is no output despite the files being very different. Apparently, compare-object doesn't consider order.
    – cgmb
    Feb 4, 2015 at 6:58
  • 3
    @cgmb - You can use -SyncWindow 0 to fix that, I believe, though I'm unsure if it's only recently been introduced. It's not particularly smart about it, though. Jan 28, 2016 at 14:49
  • 2
    Note that this is terribly slow when comparing big files. DOS' fc.exe or *nix' diff are better options there.
    – geronimo
    Sep 2, 2020 at 7:28
  • @cgmb can't reproduce with files 1 2 3, 3 2 1. What was your example?
    – alexei
    Nov 17, 2023 at 22:12
74

A simpler way of doing it is to write:

diff (cat file1) (cat file2)
3
  • 30
    Diff and cat are just aliases for Compare-Object and Get-Content in PowerShell. It is the same thing.
    – user47078
    Feb 10, 2012 at 1:54
  • 11
    despite this being the same as the accepted answer, I like using this syntax more Jan 12, 2018 at 18:41
  • 6
    Note that it doesn't behave like *nix diff at all, as other answers here note. And when I used a more complex expression in place of cat I got incorrect output, so I'll join the others in the recommendation to avoid doing this in PowerShell if you come from *nix.
    – Nickolay
    Sep 3, 2019 at 12:43
47

Or you could use the DOS fc command like so (This shows the output of both files so you will have to scan for the differences):

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

fc is an alias for the Format-Custom cmdlet so be sure to enter the command as fc.exe. Please note that many DOS utilities don't handle UTF-8 encoding.

You can also spawn a CMD process and run fc within it.

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

This instructs PowerShell to start a process with the 'cmd' program using the parameters in quotes. In the quotes, is the '/c' cmd option to run the command and terminate. The actual command to run by cmd in the process is fc filea.txt fileb.txt redirecting the output to the file diff.txt.

You can use the DOS fc.exe from within powershell.

4
  • 3
    +1 for bring out the DOS ^_^
    – Jeff B
    Apr 17, 2013 at 15:21
  • 1
    "fc" was not working for me, and I didn't realize I had to specify it as "fc.exe" to differentiate it from Format-Custom. Exactly what I was looking for. Thanks.
    – Xonatron
    Sep 17, 2017 at 13:44
  • 1
    Maybe I'm a complete philistine, but this seems much more useable to me. It solved my problem very nicely.
    – AJ.
    Jul 2, 2018 at 10:03
  • 1
    The only problem is it HATES unicode. Dec 18, 2018 at 11:57
9

diff on *nix is not part of the shell, but a separate application.

Is there any reason you can't just use diff.exe under PowerShell?

You can download a version from the UnxUtils package (http://unxutils.sourceforge.net/)

3
  • 12
    Because PowerShell is included now, nothing to download and install.
    – Bratch
    Jul 31, 2012 at 16:34
  • 2
    I just ended up using git diff, because I already had it installed. Neither fc.exe nor Compare-Object produced the output I expected. Aug 28, 2018 at 11:40
  • I rather not download essential utilities from a developer that not only uses an ambiguous date format but also switches between different formats in the same list (What is new: 10/28/00... 27-06-03...). Microsoft may love Linux but not it's core utilities...
    – ndemou
    Jul 7, 2021 at 10:50
8

compare-object (aka diff alias) is pathetic if you expect it to behave something like a unix diff. I tried the diff (gc file1) (gc file2), and if a line is too long, I can't see the actual diff and more importantly, I can't tell which line number the diff is on.

When I try adding -passthru, I now can see the difference, but I lose which file the difference is in, and I still don't get a line number.

My advice, don't use powershell to find differences in files. As someone else noted, fc works, and works a little better than compare-object, and even better is downloading and using real tools like the unix emulator that Mikeage mentioned.

2
  • It also appears to do a set comparison (i.e. ignoring the order) as -SyncWindow is maxint by default. Setting that to 0 doesn't make it work like diff either... And when I passed a pipe (... | select-object ...) as input, it just printed nonsense, so I gave up.
    – Nickolay
    Sep 3, 2019 at 12:54
  • Compare-Object isn't pathetic, it's intended to "compares two sets of objects" (see Get-Help Compare-Object | more). Not what you're trying to do. Regarding the cut-off output, PowerShell commands return objects that can be scripted/piped without parsing. If you're interested in text output, check out the Format-* cmdlets or pipe to your favorite editor and get the line numbers you want.
    – Vimes
    May 8, 2020 at 22:47
6

fc.exe is better for text comparing since it designed to work like *nix diff, i.e. compares lines sequentially, showing the actual differences and trying to re-synchronise (if the differing sections have different lengths). It also has some useful control options (text/binary, case sensitivity, line numbers, resynchronisation length, mismatch buffer size) and provides exit status (-1 bad syntax, 0 files same, 1 files differ, 2 file missing). Being a (very) old DOS utility, it does have a few limitations. Most notably, it does not automatically work with Unicode, treating the 0 MSB of ASCII characters as a line terminator so the file becomes a sequence of 1 character lines (@kennycoc: use the /U option to specify BOTH files are Unicode, WinXP onwards) and it also has a hard line buffer size of 128 characters (128 bytes ASCII, 256 bytes Unicode) so long lines get split up and compared separately.

compare-object is designed to determine if 2 objects are member-wise identical. if the objects are collections then they are treated as SETS (see help compare-object), i.e. UNORDERED collections without duplicates. 2 sets are equal if they have the same member items irrespective of order or duplications. This severely limits its usefulness for comparing text files for differences. Firstly, the default behaviour collects the differences until the entire object (file = array of strings) has been checked thus losing the information regarding the position of the differences and obscuring which differences are paired (and there is no concept of line number for a SET of strings). Using -synchwindow 0 will cause the differences to be emitted as they occur but stops it from trying to re-synchronise so if one file has an extra line then subsequent line comparisons can fail even though the files are otherwise identical (until there is a compensatory extra line in the other file thereby realigning the matching lines). However, powershell is extremely versatile and a useful file compare can be done by utilising this functionality, albeit at the cost of substantial complexity and with some restrictions upon the content of the files. If you need to compare text files with long (> 127 character) lines and where the lines mostly match 1:1 (some changes in lines between files but no duplications within a file such as a text listing of database records having a key field) then by adding information to each line indicating in which file it is, its position within that file and then ignoring the added information during comparison (but including it in the output) you can get a *nix diff like output as follows (alias abbreviations used):

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

where xx is the length of the longest line + 9

Explanation

  • (gc file | % -begin { $ln=0 } -process { '{0,6}<<:{1}' -f ++$ln,$_ }) gets the content of the file and prepends the line number and file indicator (<< or >>) to each line (using the format string operator) before passing it to diff.
  • -property { $_.substring(9) } tells diff to compare each pair of objects (strings) ignoring the first 9 characters (which are the line number and file indicator). This utilises the ability to specify a calculated property (the value of a script block) instead of the name of a property.
  • -passthru causes diff to output the differing input objects (which include the line number and file indicator) instead of the differing compared objects (which don't).
  • sort-object then puts all the lines back into sequence.
    out-string stops the default truncation of the output to fit the screen width (as noted by Marc Towersap) by specifying a width big enough to avoid truncation. Normally, this output would be put into a file which is then viewed using a scrolling editor (e.g. notepad).

Note

The line number format {0,6} gives a right justified, space padded 6 character line number (for sorting). If the files have more than 999,999 lines then simply change the format to be wider. This also requires altering the $_.substring parameter (3 more than the line number width) and the out-string xx value (maximum line length + $_.substring parameter).

1
  • The long solution given by Mr Shunz is elegantly designed for a nice readable output. Nonetheless, it has got an inherent issue: It does not return line movements (such as a couple of swapped lines). For example, if file 1 contains lines 1, 2 and 3, and file 2 contains lines 1, 3 and 2, no differences will be reported. Mar 5, 2020 at 17:35
4

WinMerge is another good GUI-based diff tool.

1
  • 1
    This is how I did it in the past, which is a manual process, that I wanted to replace with a small script.
    – Bratch
    Jul 31, 2012 at 16:35
3

As others have noted, if you were expecting a unix-y diff output, using the powershell diff alias would let you down hard. For one thing, you have to hold it's hand in actually reading files (with gc / get-content). For another, the difference indicator is on the right, far from the content -- it's a readability nightmare.

The solution for anyone looking for a sane output is

  1. get a real diff (eg from GnuWin32)
  2. edit %USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
  3. add the line

    remove-item alias:diff -force
    

The -force argument is required because Powershell is quite precious about this particular inbuilt alias. If anyone is interested, having GnuWin32 installed, I also include the following in my powershell profile:

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

Mainly because Powershell doesn't understand arguments which are run together and typing, for example "rm -Force -Recurse" is a lot more effort than "rm -rf".

Powershell has some nice features, but there are some things it should just not try to do for me.

1

There's also Windiff which provides a GUI diff interface (great for use with GUI based CVS/SVN programs)

1
  • But the question was specifically : How do I diff two text files in Windows Powershell
    – P-L
    Mar 24, 2020 at 20:10
1

This is the first question that comes up if you search for file diff in Powershell.

If you don't necessarily care what is different about the files and just want to know if they are different then I find that using Get-FileHash on each file and then comparing the two hashes is the most efficient way to do this. It's mostly useful when you have to compare a lot of files between two locations for differences.

Something like the below where the variables are the full names of the two files to compare.

function FilesAreDifferent($f1,$f2)
{
    return (Get-FileHash $f1).hash  -ne (Get-FileHash $f2).hash
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .