使用PowerShell,我想用MyValue替换给定文件中所有精确出现的[MYID]。最简单的方法是什么?


当前回答

有点旧和不同,因为我需要在特定文件名的所有实例中更改某一行。

此外,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

其他回答

有点旧和不同,因为我需要在特定文件名的所有实例中更改某一行。

此外,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

上面的只对“一个文件”运行,但你也可以对文件夹中的多个文件运行:

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

使用PowerShell中的当前工作目录,这对我来说很有效。您需要使用FullName属性,否则它将在PowerShell版本5中不起作用。我需要在所有CSPROJ文件中更改目标. net框架版本。

gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
 Set-Content "$($_.FullName)"}

我更喜欢使用。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键来步进那里的方法。