Reputation: 53
I have text1.txt file with following content:
sometext_1
--start
sometext_2.1
sometext_2.2
...
sometext_2.n
--end
sometext_3
and text2.txt file with following content:
--start
sometext_2_new1
sometext_2_new2
...
sometext_2_newn
--end
Could someone help me to write Powershell code to update content of text1.txt file between keywords --start and --end with all content of file text2.txt? So the new text1.txt will look like below:
sometext_1
--start
sometext_2_new1
sometext_2_new2
...
sometext_2_newn
--end
sometext_3
UPDATE: I'm really new in Powershell. After some research I was able to came up with following which is still not giving me what I need:
param(
[string]$location
)
$contentStart = Get-Content "c:\text2.txt"
$configFiles = Get-ChildItem $location\*.txt -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace "--start.*?(--end)", $contentStart } |
Out-File $file.PSPath
}
But it works only if text1.txt has keywords --start and --end in one line and relult is following (inserted content do not have endline symbols):
sometext_1
--start sometext_2_new1 sometext_2_new2 ... sometext_2_newn --end
sometext_3
Upvotes: 1
Views: 1454
Reputation:
I like Regex101.com to test and refine the Regular Expression I develop.
See here your example
You need to tell the RegEx with:
m
flag that ^
and $
match line begin/ends
flag that the .
dot also matches new linePS> $text1 = Get-Content ".\text1.txt"
PS> $text2 = Get-Content ".\text2.txt"
PS> $text1 -replace "(?ms)^--start$.*?^--end$",$text2
sometext_1
--start
sometext_2.1
sometext_2.2
...
sometext_2.n
--end
sometext_3
Upvotes: 2
Reputation: 32230
It's a bit involved because you need to create a regular expression with SingleLine mode.
Try something like this:
foreach ($file in $configFiles)
{
Get-Content $file.PSPath -Raw |
ForEach-Object { $_ -replace "(?s)(--start`r`n).*?(`r`n--end)", "`$1$contentStart`$2" } |
Out-File $file.PSPath
}
Explanation:
The -Raw
switch for Get-Content
tells the cmdlet to get everything as one single string, rather than an array of lines like it normally does.
There's only one item going through the pipeline now for each file, but we still need the ForEach-Object
cmdlet to enumerate the item for us.
Now, to explain the regex:
"(?s)(--start`r`n).*?(`r`n--end)"
The (?s)
is the regular expression option for single line mode. This means that the .
character will match line endings. Normally it doesn't.
Next, there's the rest of the regex, (--start`r`n).*?(`r`n--end)
. The --start
and --end
are pretty obvious. The Windows line ending characters are `r
is expressed as \r
for carriage return in most other languages and `n
is \n
for end of line in most other languages. They need to be included in order for the .*?
not to eat them in single line mode. The parentheses are for grouping for backreferences. The first parenthetic group will become $1
, and the second will become $2
, etc.
Note that if your text file is not using Windows line endings you may need to modify this regex appropriately.
The replace string:
"`$1$contentStart`$2"
Here, we're using double quotes so that the PowerShell variable, $contentStart
can be inlined into the string. And $1
and $2
are present as the backreference variables to the groups in the regular expression. However, we run into a problem with the backreference variables. They're $1
and $2
, which are valid variables in PowerShell. So, we need to escape the dollar sign with another backtick.
Upvotes: 3