使用PowerShell,我想用[MYID]
替换给定文件中所有确切出现的MyValue
。最简单的方法是什么?
使用(V3版):
(Get-Content c:\temp\test.txt).replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt
或者对于V2:
(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt
Set-Content命令的小校正。如果未找到搜索到的字符串,则Set-Content
命令将空白(清空)目标文件。
您可以先验证您要查找的字符串是否存在。如果不是,它将不会取代任何东西。
If (select-string -path "c:\Windows\System32\drivers\etc\hosts" -pattern "String to look for") `
{(Get-Content c:\Windows\System32\drivers\etc\hosts).replace('String to look for', 'String to replace with') | Set-Content c:\Windows\System32\drivers\etc\hosts}
Else{"Nothing happened"}
在搜索了太多之后,我想出了最简单的一行来做到这一点而不改变编码是:
Get-Content path/to/file.ext | out-file -encoding ASCII targetFile.ext
(Get-Content file.txt) |
Foreach-Object {$_ -replace '\[MYID\]','MyValue'} |
Out-File file.txt
请注意(Get-Content file.txt)
周围的括号是必需的:
如果没有括号,则一次读取一行内容,然后沿着管道向下流动,直到它到达out-file或set-content,这会尝试写入同一个文件,但它已经被get-content打开了,你得到了一个错误。括号使内容读取的操作执行一次(打开,读取和关闭)。只有当所有行都被读取时,它们才会一次一个地传送,当它们到达管道中的最后一个命令时,它们就可以写入文件。它与$ content = content相同; $ content |哪里......
我更喜欢使用.NET的File-class及其静态方法,如以下示例所示。
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
与Get-Content一样,这样做的好处是可以使用单个String而不是String-array。这些方法还可以处理文件的编码(UTF-8 BOM等),而无需在大多数情况下进行操作。
与使用Get-Content和管道到Set-Content的算法相比,这些方法不会弄乱行结尾(可能使用的Unix行结尾)。
所以对我来说:这些年来可能会破坏的事情会减少。
使用.NET类时,一个鲜为人知的事情是,当您在PowerShell窗口中键入“[System.IO.File] ::”时,可以按Tab键逐步执行这些方法。
上面的那个只运行“One File”,但你也可以为你文件夹中的多个文件运行:
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}
你可以尝试这样的事情:
$path = "C:\testFile.txt"
$word = "searchword"
$replacement = "ReplacementText"
$text = get-content $path
$newText = $text -replace $word,$replacement
$newText > $path
这是我使用的,但它在大文本文件上很慢。
get-content $pathToFile | % { $_ -replace $stringToReplace, $replaceWith } | set-content $pathToFile
如果您要替换大文本文件中的字符串并且速度是一个问题,请查看使用System.IO.StreamReader和System.IO.StreamWriter。
try
{
$reader = [System.IO.StreamReader] $pathToFile
$data = $reader.ReadToEnd()
$reader.close()
}
finally
{
if ($reader -ne $null)
{
$reader.dispose()
}
}
$data = $data -replace $stringToReplace, $replaceWith
try
{
$writer = [System.IO.StreamWriter] $pathToFile
$writer.write($data)
$writer.close()
}
finally
{
if ($writer -ne $null)
{
$writer.dispose()
}
}
(上面的代码尚未经过测试。)
使用StreamReader和StreamWriter替换文档中的文本可能有一种更优雅的方式,但这应该会给你一个很好的起点。
这对我使用PowerShell中的当前工作目录。您需要使用FullName
属性,否则它将无法在PowerShell版本5中运行。我需要在所有CSPROJ
文件中更改目标.NET框架版本。
gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
Set-Content "$($_.FullName)"}
有点旧和不同,因为我需要在特定文件名的所有实例中更改某一行。
此外,Set-Content
没有返回一致的结果,所以我不得不求助于Out-File
。
代码如下:
$FileName =''
$OldLine = ''
$NewLine = ''
$Drives = Get-PSDrive -PSProvider FileSystem
foreach ($Drive in $Drives) {
Push-Location $Drive.Root
Get-ChildItem -Filter "$FileName" -Recurse | ForEach {
(Get-Content $_.FullName).Replace($OldLine, $NewLine) | Out-File $_.FullName
}
Pop-Location
}
这是PowerShell版本最适合我的方法:
Major.Minor.Build.Revision
5.1.16299.98
归功于@ rominator007
我把它包装成一个函数(因为你可能想再次使用它)
function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
$content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
[System.IO.File]::WriteAllText("$FullPathToFile", $content)
}
注意:这不是区分大小写!!!!!
看到这篇文章:String.Replace ignoring case