1

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
2
  • 2
    Do you have anything to start from? "Please write code for me" posts are generally discouraged. The proper code will be more useful if you understand it as well. Commented Jul 10, 2017 at 20:50
  • I've updated my question. Commented Jul 10, 2017 at 21:11

2 Answers 2

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

It gives me empty output file.
2

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/end
  • s flag that the . dot also matches new line

PS> $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

1 Comment

I do like your regex better than mine. I'd forgotten about the multiline option. I'm not sure if it will delete the --start and --end lines though?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.