Home > database >  Powershell: Replace only fist occurence of a line/string in entire file
Powershell: Replace only fist occurence of a line/string in entire file

Time:12-08

I have following beggining of a Powershell script in which I would like to replace the values of variables for different enviroment.

$SomeVar1 = "C:\path\to\file\a"
$SomeVar1 = "C:\path\to\file\a" # Copy for test - Should not be rewriten
$SomeVar2 = "C:\path\to\file\b" 
# Note $SomeVar1 = "C:\path\to\file\a" - Should not be rewriten

When I run the rewrite script, the result should look like this:

$SomeVar1 = "F:\different\path\to\file\a"
$SomeVar1 = "C:\path\to\file\a" # Copy for test - Should not be rewrite
$SomeVar2 = "F:\different\path\to\file\b" 
# Note $SomeVar1 = "C:\path\to\file\a" - Should not be rewriten

Current script that does(n't) rewrite:

$arr = @(
   [PSCustomObject]@{Regex = '$SomeVar1 = "';  Replace = '$SomeVar1 = "F:\different\path\to\file\a"'}
   [PSCustomObject]@{Regex = '$SomeVar2 = "';  Replace = '$SomeVar1 = "F:\different\path\to\file\b"'}
)

for ($i = 0; $i -lt $arr.Length; $i  ) {

   $ArrRegex = [Regex]::Escape($arr[$i].Regex)
   $ArrReplace = $arr[$i].Replace
   
   # Get full line for replacement
   $Line = Get-Content $Workfile | Select-String $ArrRegex | Select-Object -First 1 -ExpandProperty Line

   # Rewrite part
   $Line = [Regex]::Escape($Line)
   $Content = Get-Content $Workfile
   $Content -replace "^$Line",$ArrReplace | Set-Content $Workfile
}

This replaces all the occurences in file on the start of the line (and I need only the 1st one) and doest not replace the one in Note which is okay.

Then I found this Powershell: Replace last occurence of a line in a file which does the exact oposite of what I need, only rewrites the last occurence of the string and it does it in the Note aswell and I would somehow like to change it to do the opposite - 1st occurence, line begining (Wont target the Note)

Code in my case looks like this:

# Rewrite part
$Line = [Regex]::Escape($Line)
$Content = Get-Content $Workfile -Raw
$Line = "(?s)(.*)$Line"
$ArrReplace = "`$1$ArrReplace"
$Content -replace $Line,$ArrReplace | Set-Content $Workfile

Do you have any recommendations on how to archive my goal, or is there a more sothisticated way to replace variables for powershell scripts like this?

Thanks in advance.

CodePudding user response:

You could possibly use flag variables like below to only do the first replacement for each of your regex patterns.

$Altered = Get-Content -Path $Workfile |
    Foreach-Object {
        if(-not $a) { #If replacement hasn't been done, replace
            $_ = $_ -replace 'YOUR_REGEX1','YOUR_REPLACEMENT1'
            if($_ -match 'YOUR_REPLACEMENT1') { $a = 'replacement done' } #Set Flag
        }
        if(-not $b) { #If replacement hasn't been done, replace
            $_ = $_ -replace 'YOUR_REGEX2','YOUR_REPLACEMENT2'
            if($_ -match 'YOUR_REPLACEMENT2') { $b = 'replacement done' } #Set Flag
        }
        $_ # Pipe back to $Altered
    } 
$Altered | Set-Content -Path $WorkFile

CodePudding user response:

Just reverse the RegEx, if that is what you are after:

Clear-Host
@'
abc
abc
abc
'@ -replace '^(.*?)\babc\b', '$1HelloWorld'

# Results
<#
HelloWorld
abc
abc
#>
  • Related