感谢这里的另一位用户,我能够发现 Powershell Compare-Object。
我使用的代码很简单,如下所示:
$array = Compare-Object $(Get-Content $Source1) $(Get-Content $Source2)
$array | where {$_.SideIndicator -eq "<="} | Format-Table -Property InputObject -AutoSize -HideTableHeaders | Out-File -Width 512 -Encoding utf8 NoMatchA.txt
$array | where {$_.SideIndicator -eq "=>"} | Format-Table -Property InputObject -AutoSize -HideTableHeaders | Out-File -Width 512 -Encoding utf8 NoMatchB.txt
我正在比较的文件是哈希值+文件路径,看起来像这个测试输入源A:
0004250736cc617f596b24d69c52a1276ea7f81cd5f7c7e49458894987d02538 D:\Documents\Server\DBackupServer\snapraid\Archive\authors.txt
5a10fd71a62ca272908ded8a7f20826722c0fc67da22256accb42159baa13af2 D:\Documents\Server\DBackupServer\snapraid\Archive\copying.txt
d3d868c751b91c5bd5105db5b9c4f35429fe85a6405bf7fa073d969a0f24a4bc D:\Documents\Server\DBackupServer\snapraid\Archive\history.txt
a1ca63b535996640ac4c5ae0fb91998ebcb495928a637d8d8f71508573c289bd D:\Documents\Server\DBackupServer\snapraid\Archive\install.txt
62f9bfd975bc0773be108b20467d6ece969e06e033b5ae51fb56597d09800000 D:\Documents\Server\DBackupServer\snapraid\Archive\readme.txt
来源B:
0004250736cc617f596b24d69c52a1276ea7f81cd5f7c7e49458894987d00000 E:\Documents\Server\DBackupServer\snapraid\Archive\authors.txt
06d99bb9e6b9c0f57828b29a465a769628da86faca48a104fbdd3263d85eda4d E:\Documents\Server\DBackupServer\snapraid\Archive\backup_snapraid.bat
5a10fd71a62ca272908ded8a7f20826722c0fc67da22256accb42159baa13af2 E:\Documents\Server\DBackupServer\snapraid\Archive\history.txt
a1ca63b535996640ac4c5ae0fb91998ebcb495928a637d8d8f71508573c289bd E:\Documents\Server\DBackupServer\snapraid\Archive\install.txt
62f9bfd975bc0773be108b20467d6ece969e06e033b5ae51fb56597d098969f3 E:\Documents\Server\DBackupServer\snapraid\Archive\readme.txt
但我希望它忽略驱动器号,这样我就可以比较来自两个不同来源的两个文件。现在我通过for /f
批处理文件中的命令运行哈希日志文件以删除驱动器号,但对于大量条目来说,这可能需要很长时间。
是否有任何方法可以让比较对象忽略驱动器号?:
是驱动器号的唯一标识符(尽管最终希望它与 UNC 前缀一起使用\\
),并且考虑到哈希,它应该始终处于相同的位置,所以也许这可能会有所帮助。
我尝试使用该Split()
命令,虽然我可以根据空格字符拆分对象,但我不确定如何将其实现到比较对象中。
我尝试使用:get-content $Source1 | foreach {$_ -replace "D:", ""} | Set-Content "$Source1a"
这与批处理文件一样长......
谢谢你的帮助。
编辑:感谢大家到目前为止的帮助。我还没有机会测试这个提案,明天应该会测试。
无论如何,为了澄清起见,我正在寻找三个文件输出:
- 文件在 A 中而不在 B 中- 输出格式与输入相同(哈希 + 文件路径/名称),但仅比较文件名/路径,以识别源 A 中不在源 B 中的文件。
从上面的测试输入,结果输出将是“FileAnotInB.txt”:
5a10fd71a62ca272908ded8a7f20826722c0fc67da22256accb42159baa13af2 D:\Documents\Server\DBackupServer\snapraid\Archive\copying.txt
- 文件在 B 中而不在 A 中- 输出格式与输入相同(哈希 + 文件路径/名称),但仅比较文件名/路径,以识别源 B 中不在源 A 中的文件。
从上面的测试输入,结果输出将是“FileBnotInA.txt”:
06d99bb9e6b9c0f57828b29a465a769628da86faca48a104fbdd3263d85eda4d E:\Documents\Server\DBackupServer\snapraid\Archive\backup_snapraid.bat
- 哈希不匹配- 输出格式与输入相同(哈希值 + 文件名路径),但仅比较哈希值,以识别不匹配的哈希值,最好将源 A 和源 B 同时输出以进行简单比较:
从上面的测试输入,结果输出将是(注意在测试哈希末尾替换 00000)“FailedHashes.txt”:
0004250736cc617f596b24d69c52a1276ea7f81cd5f7c7e49458894987d02538 D:\Documents\Server\DBackupServer\snapraid\Archive\authors.txt
0004250736cc617f596b24d69c52a1276ea7f81cd5f7c7e49458894987d00000 D:\Documents\Server\DBackupServer\snapraid\Archive\authors.txt
62f9bfd975bc0773be108b20467d6ece969e06e033b5ae51fb56597d09800000 E:\Documents\Server\DBackupServer\snapraid\Archive\readme.txt
62f9bfd975bc0773be108b20467d6ece969e06e033b5ae51fb56597d098969f3 E:\Documents\Server\DBackupServer\snapraid\Archive\readme.txt
看起来 JosefZ 的回复可能会这样做,或者至少我可以调整它来做到这一点。我必须测试一下才能知道,但我想编辑一下以澄清并感谢您的帮助!
答案1
以下代码片段展示了如何忽略驱动器号的可能方法:
Compare-Object $((Get-Content $Source1) -replace "\s[A-Z]\:\\", ' \') $((Get-Content $Source2) -replace "\s[A-Z]\:\\", ' \')
… 有没有一种简单的方法,也可以使用 compare-object 和/或 where-object 来输出一个文件,显示文件名匹配但哈希文件不匹配的位置?我最终的目标是三个文件:源 A 中的文件不在 B 中。源 B 中的文件不在 A 中。然后是文件名/路径相同但哈希文件不匹配?
我不确定这种三分法是否如上述补充要求中所述定义明确。不过,这是我解决它的尝试(略微更改了变量和文件名):
$sourcePath = 'D:\PShell\DataFiles'
$utf8 = 'utf8' # $utf8 = 'Default' # debugged using Default
$sourceA = "$sourcePath\1558327A.txt"
$sourceB = "$sourcePath\1558327B.txt"
$contentA = (Get-Content -Path $SourceA)
$contentB = (Get-Content -Path $SourceB)
$array = Compare-Object -ReferenceObject $(
$contentA -replace "\s[A-Z]\:\\", ' \') -DifferenceObject $(
$contentB -replace "\s[A-Z]\:\\", ' \')
$arrNotInB = $array | Where-Object {$_.SideIndicator -eq "<="} # | Select-Object -ExpandProperty InputObject #|
$arrNotInA = $array | Where-Object {$_.SideIndicator -eq "=>"} # | Select-Object -ExpandProperty InputObject #|
# Files in Source B not in A.
$arrNotInA |
Select-Object -ExpandProperty InputObject |
Where-Object {
-not ($arrNotInB -match [regex]::Escape($($_ -split '\s', 2)[1]))
} | Out-File -Width 512 -Encoding $utf8 -FilePath "$sourcePath\NotInA.txt"
# Files in source A not in B.
$arrNotInB |
Select-Object -ExpandProperty InputObject |
Where-Object {
-not ($arrNotInA -match [regex]::Escape($($_ -split '\s', 2)[1]))
} | Out-File -Width 512 -Encoding $utf8 -FilePath "$sourcePath\NotInB.txt"
# And then same filenames/paths but with mismatched hash
(
$arrNotInB |
Select-Object -ExpandProperty InputObject |
Where-Object {
($arrNotInA -match [regex]::Escape($($_ -split '\s', 2)[1]))
} | ForEach-Object {
$auxHash, $auxPath = $_ -split '\s', 2
$contentA | Where-Object {
($_ -replace "\s[A-Z]\:\\", ' \') -match [regex]::Escape("$auxHash $auxPath")
}
}
),(
$arrNotInA |
Select-Object -ExpandProperty InputObject |
Where-Object {
($arrNotInB -match [regex]::Escape($($_ -split '\s', 2)[1]))
} | ForEach-Object {
$auxHash, $auxPath = $_ -split '\s', 2
$contentB | Where-Object {
($_ -replace "\s[A-Z]\:\\", ' \') -match [regex]::Escape("$auxHash $auxPath")
}
}
) | Out-File -Width 512 -Encoding $utf8 -FilePath "$sourcePath\NotMatchHash.txt"
答案2
样本数据:
# --- SourceA -- --- SourceB --
# -------------- --------------
# 123 c:\123.txt 123 c:\123.txt <-- FullMatch
# 456 c:\456.txt 789 c:\789.txt <-- NoMatch
# 0ab c:\0ab.txt 0ab d:\0ab.txt <-- Hash + RelPathMatch
创建示例文件:
@'
123 c:\123.txt
456 c:\456.txt
0ab c:\0ab.txt
'@ | Set-Content A.txt
@'
123 c:\123.txt
789 c:\789.txt
0ab d:\0ab.txt
'@ | Set-Content B.txt
Import-Csv
如果您可以控制源文件的创建,则可以将以下内容简化为一个操作:
Function Import-Log ($Path) {
Get-Content $Path | ForEach{
$_ -match '(^.+ )[A-Za-z]\:\\(.+$)' | out-null
[PSCustomObject]@{
Full = $matches[0]
NoDrive = $matches[1] + $matches[2]
}
}
}
根据上述函数定义:
$oA = Import-Log A.txt
$oB = Import-Log B.txt
$NoMatches = Compare-Object $oA $oB -Property NoDrive
$AnotB = $NoMatches | ? SideIndicator -like '<='
$BnotA = $NoMatches | ? SideIndicator -like '=>'
$HashMatch = Compare-Object $oA $oB -Property Full, NoDrive | ? NoDrive -notIn $NoMatches.NoDrive
结果:
PS C:\> $NoMatches
NoDrive SideIndicator
------- -------------
789 789.txt =>
456 456.txt <=
PS C:\> $AnotB
NoDrive SideIndicator
------- -------------
456 456.txt <=
PS C:\> $BnotA
NoDrive SideIndicator
------- -------------
789 789.txt =>
PS C:\> $HashMatch
full NoDrive SideIndicator
---- ------- -------------
0ab d:\0ab.txt 0ab 0ab.txt =>
0ab c:\0ab.txt 0ab 0ab.txt <=