问题
I want to compare 2 text files and output the difference in another text file.
$Location = "c:\temp\z.txt"
compare-object (get-content c:\temp\hostname_old.txt) (get-content c:\temp\hostname_new.txt) | format-list | Out-File $Location
hostname_old.txt
server02
server05
server04
server06
server01
hostname_new.txt
server04
server01
server02
Results
InputObject : server05
SideIndicator : <=
InputObject : server06
SideIndicator : <=
This is what I want : (get rid of both InputObject and SideIndicator)
server05
server06
Note: A related problem where one input file has duplicate entries is the subject of this question.
回答1:
Just use the -PassThru parameter:
compare-object (get-content c:\temp\hostname_old.txt) (get-content c:\temp\hostname_new.txt) -PassThru | Out-File $Location
does exactly what you want.
回答2:
I guess you're looking for Select-Object -ExpandProperty InputObject
compare-object (get-content c:\temp\hostname_old.txt) (get-content c:\temp\hostname_new.txt) | Select-Object -ExpandProperty InputObject | Out-File $Location
Please note, that you cannot use format-list
in the Pipeline
before writing data into a file.
回答3:
Update: Palle Due's helpful answer offers the best solution.
This answer may still be of interest for contrasting member enumeration with pipeline use, a discussion of output formatting, and contrasting Out-File
with Set-Content
.
In PSv3+ you can simply use member enumeration to extract the .InputObject
values:
PS> (Compare-Object (Get-Content old.txt) (Get-Content new.txt)).InputObject
server05
server06
Note:
Member enumeration is convenient and fast, but at the expense of memory consumption, which can be a problem with very large collections (not here). The output from
Compare-Object
must be collected in memory as a whole in an array ([object[]]
), and, similarly, the.InputObject
property values are returned as an array.For slower, but memory-friendly streaming (one-by-one processing), use the pipeline with
Select-Object -ExpandProperty
, as in TobyU's effective solution.
Re saving to a file: piping to Out-File $location
(or, more succinctly, using output redirection: > $location
) is sufficient - no need for Format-List
.
In general, note that the purpose of the Format-*
cmdlets is to produce output for display, not for programmatic processing and persistence.
That said, Out-File
/ >
(effectively) uses the Format-*
cmdlets behind the scenes to produce a string representation of the input objects, just like the default console output, which is why it's not the right command for persisting arbitrary input objects.
Use of Out-File
/ >
with strings is safe, however, because they are output as-is. By contrast, even numbers are problematic if they have decimal places, because they are stringified with the current culture's decimal separator (e.g., ,
rather than .
in some cultures).
If your input objects are strings, you can alternatively use Set-Content
, which is faster than Out-File
/ >
, but the caveat is that in Windows PowerShell the character encoding used by default differs: Out-File
/ >
produces UTF-16LE files by default, whereas Set-Content
uses the legacy system locale's "ANSI" code page (typically, a single-byte 8-bit encoding such as Windows-1252).
By contrast, in PowerShell Core both cmdlets produce BOM-less UTF-8.
Note that Set-Content
, unlike Out-File
, stringifies non-string objects simply by calling the .ToString()
method on them.
来源:https://stackoverflow.com/questions/54571540/compare-two-text-files-and-write-the-differences-to-text-file