PowerShell command to replace a chunk of text in a file

一个人想着一个人 提交于 2019-12-05 16:36:34
Keith Hill

Here's how I would go about this. First, when you need to get the entire contents of a file for purposes like replacing text over multiple lines, don't use Get-Content. Instead, use [IO.file]::ReadAllText().

Then use the -replace operator, for example:

[IO.File]::ReadAllText("$pwd\foo.sql") -replace `
   '(?s).*?(USE \[\$\(DatabaseName\)\].*)$',"foo`n`$1" > foo.sql

Here I'm replacing the beginning text with "foo". Also note that to get the regex used by -replace to match across newlines I prefix the regex with (?s) - single-line mode.

Mjolinor brings up a good point, in the case where the replacement text has characters that could be interpreted as regex special variables e.g. $1, $2, etc. While you can use [regex]::escape() to escape the regex there's still PowerShell code that will interpret $<something> as a variable or start of a sub-expression. In this case, it's pretty simple to work around by just capturing the part you want to keep with the -replace operator and then prepend the new text in a second step e.g.:

$keep = [IO.File]::ReadAllText("$pwd\foo.sql") -replace `
            '(?s).*?(USE \[\$\(DatabaseName\)\].*)$','$1'
$newText + $keep > foo.sql

Note that in the replace in this case, I use single quotes around $1 which prevents PowerShell from interpreting any special PowerShell characters. It's kind of like a verbatim string in C#.

stackoverflowuser

I ended up doing the below. I find it easier to understand.

$fileContent = [System.Io.File]::ReadAllText($filePath)
$toReplace = [System.Io.File]::ReadAllText($anotherPath)
$afterReplace = $fileContent.Replace($toReplace,$newContent)
[System.Io.Directory]::WriteAllText($filePath,$afterReplace)
Andy Schneider

In Get-Content, you can set the ReadCount to 0. This will create an array of one item. You can access it via $contents[0]:

$contents = Get-Content file.sql -ReadCount 0
$contents[0].Replace($oldstring, $newString)

You can also pipe the whole thing to Out-String, but I think the first option would be a bit faster.

mjolinor

Assuming your replacement text is in newscript.txt:

 $new = Get-Content newscript.txt

 Get-Content file.sql | % {
     if ($_ -eq 'USE [$(DatabaseName)]') {
         $test = $true
     }
     if ($test) {
         $new += $_
     }
 }

 $new | Out-File newfile.sql
JPBlanc

After a script solution, a command line solution. Assuming your replacement text is in newscript.txt:

# Read the file $file into an array of lines
PS > $file = Get-Content 'C:\temp\sql.txt'

# Retrieve the line beginning the replacement
PS > $begin  =  $file | Select-String -Pattern 'USE \[\$\(DatabaseName\)\]' 
PS > $begin.linenumber
17

# Selecting (in a new array) the last computed lines
PS > $secondPart = $file | Select-Object -Last ($file.count - $begin.linenumber +1) 
PS > $secondPart
USE [$(DatabaseName)]
.......
.........
..... MORE SQL SCRIPT

# Creating the new file
PS > $new = Get-Content newscript.txt
PS > ($new + $secondPart) | Out-File newfile.sql
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!