使用PowerShell,我想用MyValue替换给定文件中所有精确出现的[MYID]。最简单的方法是什么?
当前回答
对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 $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替换文档中的文本可能还有一种更优雅的方式,但这应该是一个很好的起点。
我更喜欢使用。net的file类和它的静态方法,如下面的例子所示。
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
这样做的优点是使用单个String,而不是像Get-Content那样使用String数组。这些方法还负责文件的编码(UTF-8 BOM等),而不需要您在大多数时候负责。
此外,与使用Get-Content和管道连接到Set-Content的算法相比,这些方法不会弄乱行结束符(可能会使用Unix行结束符)。
所以对我来说:几年下来会坏掉的东西更少。
在使用. net类时,一个鲜为人知的事情是,当您键入“[System.IO.”在PowerShell窗口中,您可以按Tab键来步进那里的方法。
上面的只对“一个文件”运行,但你也可以对文件夹中的多个文件运行:
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}
如果需要替换多个文件中的字符串:
值得注意的是,这里发布的不同方法在完成所需时间方面可能有很大不同。对我来说,我经常有大量的小文件。为了测试哪个性能最好,我在40,693个单独的文件中提取了5.52 GB(5,933,604,999字节)的XML,并运行了我在这里找到的三个答案:
## 5.52 GB (5,933,604,999 bytes) of XML files (40,693 files)
$xmls = (Get-ChildItem -Path "I:\TestseT\All_XML" -Recurse -Filter *.xml).FullName
#### Test 1 - Plain Replace
$start = Get-Date
foreach ($xml in $xmls) {
(Get-Content $xml).replace("'", " ") | Set-Content $xml
}
$end = Get-Date
New-TimeSpan –Start $Start –End $End
# TotalMinutes: 103.725113128333
#### Test 2 - Replace with -Raw
$start = Get-Date
foreach ($xml in $xmls) {
(Get-Content $xml -Raw).replace("'", " ") | Set-Content $xml
}
$end = Get-Date
New-TimeSpan –Start $Start –End $End
# TotalMinutes: 10.1600227983333
#### Test 3 - .NET, System.IO
$start = Get-Date
foreach ($xml in $xmls) {
$txt = [System.IO.File]::ReadAllText("$xml").Replace("'"," ")
[System.IO.File]::WriteAllText("$xml", $txt)
}
$end = Get-Date
New-TimeSpan –Start $Start –End $End
# TotalMinutes: 5.83619516833333
(Get-Content file.txt) |
Foreach-Object {$_ -replace '\[MYID\]','MyValue'} |
Out-File file.txt
注意(Get-Content file.txt)周围的括号是必需的:
Without the parenthesis the content is read, one line at a time, and flows down the pipeline until it reaches out-file or set-content, which tries to write to the same file, but it's already open by get-content and you get an error. The parenthesis causes the operation of content reading to be performed once (open, read and close). Only then when all lines have been read, they are piped one at a time and when they reach the last command in the pipeline they can be written to the file. It's the same as $content=content; $content | where ...
推荐文章
- 如何在PowerShell中获得本地主机名?
- PowerShell:如何将数组对象转换为PowerShell中的字符串?
- 从PowerShell ISE中的另一个PS1脚本调用PowerShell脚本PS1
- 如何运行一个PowerShell脚本而不显示窗口?
- PowerShell:仅为单个命令设置环境变量
- 是否有一种方法可以通过双击.ps1文件来使PowerShell脚本工作?
- PowerShell等价于grep -f
- “Write-Host”,“Write-Output”,或“[console]::WriteLine”之间的区别是什么?
- Powershell相当于bash的&号(&),用于分叉/运行后台进程
- PowerShell脚本在机器上返回。net框架的版本?
- 如何在PowerShell中获得MD5校验和
- 如何在PowerShell格式化日期时间
- PowerShell和-contains操作符
- 使用PowerShell删除超过15天的文件
- 数组添加 vs +=