Reputation: 13
So I have a Pipe that will search a file for a specific stream and if found will replace it with a masked value, I am trying to have a counter for all of the times the oldValue is replaced with the newValue. It doesn't necessarily need to be a one liner just curious how you guys would go about this. TIA!
Get-Content -Path $filePath |
ForEach-Object {
$_ -replace "$oldValue", "$newValue"
} |
Set-Content $filePath
Upvotes: 1
Views: 822
Reputation: 437708
I suggest:
Reading the entire input file as a single string with Get-Content
's -Raw
switch.
Using -replace
/ [regex]::Replace()
with a script block to determine the substitution text, which allows you to increment a counter variable every time a replacement is made.
Note: Since you're replacing the input file with the results, be sure to make a backup copy first, to be safe.
In PowerShell (Core) 7+, the -replace
operator now directly accepts a script block that allows you to determine the substitution text dynamically:
$count = 0
(Get-Content -Raw $filePath) -replace $oldValue, { $newValue; ++$count } |
Set-Content -NoNewLine $filePath
$count
now contains the number of replacements, across all lines (including multiple matches on the same line), that were performed.
In Windows PowerShell, direct use of the underlying .NET API, [regex]::Replace()
, is required:
$count = 0
[regex]::Replace(
'' + (Get-Content -Raw $filePath),
$oldValue,
{ $newValue; ++(Get-Variable count).Value }
) | Set-Content -NoNewLine $filePath
Note:
'' +
ensures that the call succeeds even if file $filePath
has no content at all; without it, [regex]::Replace()
would complain about the argument being null.
++(Get-Variable count).Value
must be used in order to increment the $count
variable in the caller's scope (Get-Variable
can retrieve variables defined in ancestral scopes; -Scope 1
is implied here, thanks to PowerShell's dynamic scoping). Unlike with -replace
in PowerShell 7+, the script block runs in a child scope.
As an aside:
Upvotes: 5
Reputation: 11
Changing my answer due to more clarifications in comments. The best way I can think of is to get the count of the $Oldvalue ahead of time. Then replace!
$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
Upvotes: 0