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


当前回答

这要归功于@rominator007

我把它包装成一个函数(因为你可能想再次使用它)

function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
    $content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
    [System.IO.File]::WriteAllText("$FullPathToFile", $content)
}

注意:这是不区分大小写的!!!!!

请看这篇文章:字符串。替换忽略大小写

其他回答

示例替换文件夹内的所有字符串:

$path=$args[0]
$oldString=$args[1]
$newString=$args[2]

Get-ChildItem -Path $path -Recurse -File | 
ForEach-Object { 
    (Get-Content $_.FullName).replace($oldString,$newString) | 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

因为这个经常出现,我为它定义了一个函数。我默认使用区分大小写、基于正则表达式的匹配,但我添加了针对文字文本和忽略大小写的开关。

# Find and replace text in each pipeline string.  Omit the -Replace parameter to delete
# text instead.  Use the -SimpleMatch switch to work with literal text instead of regular
# expressions.  Comparisons are case-sensitive unless the -IgnoreCase switch is used.
Filter Edit-String {
    Param([string]$Find, [string]$Replace='', [switch]$SimpleMatch, [switch]$IgnoreCase) 

    if ($SimpleMatch) {
        if ($IgnoreCase) {
            return $_.Replace($Find, $Replace,
                [System.StringComparison]::OrdinalIgnoreCase)
        }
        return $_.Replace($Find, $Replace)
    }
    if ($IgnoreCase) {
        return $_ -replace $Find, $Replace
    }
    return $_ -creplace $Find, $Replace
}

Set-Alias replace Edit-String
Set-Alias sc Set-Content  

使用

# 1 file
$f = a.txt; gc $f | replace '[MYID]' 'MyValue' -SimpleMatch | sc $f

# 0 to many files
gci *.txt | % { gc $_ | replace '\[MYID\]' 'MyValue' | sc $_ }

# Several replacements chained together
... | replace '[1-9]' T | replace a b -IgnoreCase | replace 'delete me' | ...

# Alias cheat sheet
#  gci Get-ChildItem
#  gc  Get-Content
#  sc  Set-Conent
#  %   ForEach-Object
(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 ...

我从帕耶特的Windows Powershell in Action中找到了一个鲜为人知但非常酷的方法。您可以像引用变量一样引用文件,类似于$env:path,但需要添加花括号。

${c:file.txt} = ${c:file.txt} -replace 'oldvalue','newvalue'