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 ,``rn
t` 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.000
is 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.