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).