Home > Net >  Powershell find text containing multiple lines, replace text in those lines, preserve the format of
Powershell find text containing multiple lines, replace text in those lines, preserve the format of

Time:11-07

I am trying to build a batch file, which finds a group of text containing multiple lines in a text-based file, replaces text within that group of lines, then saves over the existing file with the same file name.

Specifically, I want to only find the line containing 270.000 that comes after the line containing 50 and after the line containing 1 1/2", replace the 270.000 with 90.000 while preserving the first two lines containing 1 1/2" and 50.

So, find these 3 lines, replace something within the 3 lines, output to 3 lines

I want to find this combination of lines:

1 1/2"
 50
  270.000

I want this output:

1 1/2"
 50
   90.000

I want the new file to have the same file name.

I have made it this far with my batch file:

@echo off
cd/
powershell -Command "(gc C:\some_file.txt -raw) -replace '(?ms)1 1/2".*? 50.*?  270.000', '1 1/2",`r`n`t 50,`r`n`t   90.000' | Out-File -encoding ASCII C:\some_file.txt"

I get this output:

1 1/2,`r`n`t 50,`r`n`t   90.000

The double quotes are missing after the 1 1/2" and I am getting ,``rnt` literally instead of new lines.

Also, there are many of these multi-line conditions I need to find and replace so I would like to know how to have a more readable code.

CodePudding user response:

Here's something you can try using Select-String to account for the post, or pre-context of a found pattern.

$path = 'C:\some_file.txt'
$content = Get-Content -Path $path
if ((($found = $content | Select-String -Pattern '1 1\/2"' -Context 2).Context.DisplayPostContext -match '50|270').Count -eq 2)
{
    $index = $found.LineNumber   1
    $content[$index] = $content[$index] -replace '270','90'
    Set-Content -Path $path -Value $content 
}

Collecting the content inside the variable $content you can use Select-String to find the string matching 1 1/2" and compare that the following lines match either 50 or 270. Using the -Match operator against a collection of items gives you the matched content rather than a boolean value. So, the count should be 2 for the proceeding lines. Since Select-String returns a line number as well, you can use that as the index for the value that you'd like to replace. Now you just save it back to the same file (if that's youre intentions). I also didn't account for match possibilities that other lines may contain the same patterns, but the probability is too low for that.

CodePudding user response:

Since the text to replace does not have to deal with case-sensitivity here, You can simply use the string .Replace() method on this.

Just use two Here-Strings for the lines to find and the lines you want to replace them with:

$fileName = 'C:\some_file.txt'

$find = @'
1 1/2"
 50
  270.000
'@

$replace = @'
1 1/2"
 50
  90.000
'@

(Get-Content -Path $fileName -Raw).Replace($find, $replace) | Set-Content -Path $fileName

CodePudding user response:

If this 270.000is all you are looking for, then go at it directly. It should not matter what is in front or behind it if that is all you want to be changed.

Meaning, it's a single string in strings. Without using files, here's an example:

 @'
1 1/2"
 50
  270.000


1 1/2"
 50
  270.000

1 1/2"
 50
  270.000
'@ -replace '  270.000', '   90.000'

# Results
<#
1 1/2"
 50
   90.000


1 1/2"
 50
   90.000

1 1/2"
 50
   90.000
#>

The same find and replace can be used when trying to modify many files, with the Set-Content cmdlet.

  • Related