【问题标题】:Powershell eq operator saying hashes are different, while Write-Host is showing the oppositePowershell eq 运算符表示哈希不同,而 Write-Host 显示相反
【发布时间】:2021-11-16 02:17:59
【问题描述】:

我有一个脚本,它定期生成目录中所有文件的列表,然后将结果的文本文件写入不同的目录。

我想更改此设置,以便它检查输出目录中的最新文本文件,并且仅在存在差异时创建一个新文件。看起来很简单。

这是我尝试过的:

首先我获取目录中最新的文件,获取哈希,并将我的变量值写入控制台:

$lastFile = gci C:\ReportOutputDir | sort LastWriteTime | select -last 1 | Select-Object -ExpandProperty FullName
$oldHash = Get-FileHash $lastFile | Select-Object Hash
Write-Host 'lastFile = '$lastFile
Write-Host 'oldHash = '$oldHash

输出:

lastFile = C:\ReportOutputDir\test1.txt
oldHash =  @{Hash=E7787C54F5BAE236100A24A6F453A5FDF6E6C7333B60ED8624610EAFADF45521}

然后我在 FileList 目录上执行完全相同的 gci,并创建一个新文件 (new_test.txt),然后获取该文件的哈希:

gci -Path C:\FileLists -File -Recurse -Name -Depth 2 | Sort-Object | out-file C:\ReportOutputDir\new_test.txt
$newFile = gci C:\ReportOutputDir | sort LastWriteTime | select -last 1 | Select-Object -ExpandProperty FullName
$newHash = Get-FileHash $newFile | Select-Object Hash
Write-Host 'newFile = '$newFile
Write-Host 'newHash = '$newHash

输出:

newFile =  C:\ReportOutputDir\new_test.txt
newHash =  @{Hash=E7787C54F5BAE236100A24A6F453A5FDF6E6C7333B60ED8624610EAFADF45521}

最后,我尝试了我的 -eq 运算符,如果它相等,我通常会简单地删除 newFile。现在,我只是做一个简单的:

if ($newHash -eq $oldHash){
'files are equal'
}
else {'files are not equal'}

不知何故,我得到了

files are not equal

什么给了?此外,为了记录,我最初试图将 gci 输出保存到变量并将最后一个文件的内容与 gci 输出进行比较,但也遇到了 -eq 运算符的问题。对PowerShell的东西相当陌生,所以我确定我在这里做错了。

【问题讨论】:

    标签: powershell


    【解决方案1】:
    • Select-Object Hash 创建一个具有.Hash 属性对象,并且该属性包含散列字符串

    • 返回的对象是 [pscustomobject] 类型,并且此类型的两个实例从不比较相等 - 即使它们的所有属性名称和值都相等:

      • 原因是引用相等被测试了,因为[pscustomobject]是一个.NET 引用类型,它没有定义自定义相等- 测试逻辑。

      • 测试引用相等意味着只有两个引用指向同一个实例比较相等。

      • 一个简单的例子:

        PS> [pscustomobject] @{ foo = 1 } -eq [pscustomobject] @{ foo = 1 }
        False # !! Two distinct instances aren't equal, no matter what they contain.
        

    你有两个选择:

    • 比较 .Hash 属性值,而不是整个对象:

      if ($newHash.Hash -eq $oldHash.Hash) { # ...
      
    • 如果您不需要 [pscustomobject] 包装散列字符串,使用Select-Object-ExpandProperty 参数 而不是(可能是位置隐含的)-Property 参数:

      Select-Object -ExpandProperty Hash
      

    至于为什么Write-Host输出匹配:

    当您强制将对象转换为 string 表示形式时 - 本质上,Write-Host 在其参数上调用 .ToString() - 具有相同属性和值的不同 [pscustomobject] 实例的字符串表示形式将是相同的:

    PS> "$([pscustomobject] @{ foo = 1 })" -eq "$([pscustomobject] @{ foo = 1 })"
    True # Same as: '@{foo=1}' -eq '@{foo=1}'
    

    但是,您应该依赖这些哈希表-类似字符串表示来确定整个[pscustomobject]s 的相等性,因为这些表示的固有局限性,很容易产生误报

    This answer 展示了如何比较[pscustomobject] 实例作为一个整体,通过比较它们的所有属性值,通过将所有属性名称传递给Compare-Object@ 987654345@ - 但请注意,这假定所有属性值都是字符串或 .NET 值类型的实例,或者相应的属性必须再次引用相同的 .NET 引用类型实例,或者属于实现自定义相等比较的类型逻辑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-01
      • 2023-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多