【问题标题】:How to add counter into Powershells ForEach-Object function如何将计数器添加到 Powershell ForEach-Object 函数中
【发布时间】:2021-10-19 20:15:51
【问题描述】:

所以我有一个管道,它将在文件中搜索特定流,如果找到将用掩码值替换它,我试图为 oldValue 替换为 newValue 的所有时间设置一个计数器。它不一定需要是一个班轮,只是好奇你们会怎么做。蒂亚!

Get-Content -Path $filePath |
    ForEach-Object {
        $_ -replace "$oldValue", "$newValue"
    } |
    Set-Content $filePath

【问题讨论】:

  • 我怀疑您需要添加一个测试步骤来查看 $OldValue 是否在目标中。这会让你增加一个计数器。
  • 在文件的同一行多次发生替换是否重要?

标签: powershell


【解决方案1】:

我建议:

  • 使用Get-Content-Raw 开关将整个输入文件作为单个字符串读取。

  • 使用-replace / [regex]::Replace()脚本块 来确定替换文本,这样您就可以在每次替换时增加一个计数器变量。

注意:由于您将输入文件替换为结果,因此请务必先制作备份副本,以确保安全。

PowerShell (Core) 7+ 中,-replace operator 现在直接接受允许您动态确定替换文本的脚本块:

$count = 0
(Get-Content -Raw $filePath) -replace $oldValue, { $newValue; ++$count } |
  Set-Content -NoNewLine $filePath

$count 现在包含已执行的所有行(包括同一行上的多个匹配项)的替换次数。


Windows PowerShell 中,需要直接使用底层 .NET API [regex]::Replace()

$count = 0
[regex]::Replace(
  '' + (Get-Content -Raw $filePath), 
  $oldValue, 
  { $newValue; ++(Get-Variable count).Value }
) | Set-Content -NoNewLine $filePath

注意:

  • '' + 确保调用成功,即使文件$filePath 根本没有内容;没有它,[regex]::Replace() 会抱怨参数为空。

  • ++(Get-Variable count).Value 必须用于增加 调用者 作用域中的 $count 变量(Get-Variable 可以检索在祖先作用域中定义的变量;-Scope 1 在这里隐含,这要归功于PowerShell 的动态范围)。与 PowerShell 7+ 中的 -replace 不同,脚本块在 child 范围内运行。


顺便说一句:

  • 对于这个用例,使用脚本块的唯一原因是计数器变量可以递增 - 替换文本本身是静态的。请参阅 this answer 以获取真正需要动态确定替换文本的示例,方法是从手头的匹配中派生出来,并将其传递给脚本块。

【讨论】:

  • 很高兴听到这个消息,@UncommonReefer。这意味着该文件是完全空的。请参阅我的更新,它现在可以防止这种情况。另外,请允许我在下一条评论中给你标准的建议给新人:
【解决方案2】:

由于 cmets 中的更多说明而更改我的答案。我能想到的最好方法是提前计算 $Oldvalue 的数量。然后替换!

$content = Get-Content -Path $filePath

$toBeReplaced = Select-String -InputObject $content -Pattern $oldValue -AllMatches
$replacedTotal = $toBeReplaced.Matches.Count

$content | ForEach-Object {$_ -replace "$oldValue", "$newValue"} | Set-Content $filePath

【讨论】:

  • 感谢@austdav0 的回复,我实际上已经尝试过类似的方法,但在这样做时遇到了问题。如果在同一行中有两个 oldValue 实例,您的函数会增加计数吗?抱歉,新堆栈试图找出格式化 ha ' function countUpdates{ Param($filePath, $oldValue) $fileToChange = Get-Content $filePath foreach($line in $fileToChange) { if($line -like "$ oldValue") { $count = $count + 1 } }write-host $count }
  • 哇,我觉得很笨,无法弄清楚如何添加灰色代码框大声笑
  • 嘿@UncommonReefer!我已更改我的答案以更好地适合您的解决方案。我会提前检查需要更换的东西。然后更换。如果您有任何问题,请告诉我!
  • @UncommonReefer in cmets 只是将代码放在反引号之间
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-23
  • 1970-01-01
  • 1970-01-01
  • 2020-09-06
  • 2011-07-02
  • 2010-10-07
  • 2012-05-03
相关资源
最近更新 更多