PowerShell替换文件中的特定字符串当存在多个匹配时

时间:2017-11-14 20:11:32

标签: string powershell replace

问题

我试图通过替换文件中非常特定的子字符串来修改文件;但是,在此特定实例中,该文件包含两行几乎相同的行。

这一行是在AssemblyInfo文件中,我试图替换AssemblyVersion的值。见下文:

$CurrentVersion = '1.0.*'
$NewVersion = '1.0.7.1'

# Two similar lines:
// [assembly: AssemblyVersion("1.0.*")] # I want to ignore this line
[assembly: AssemblyVersion("1.0.*")] # I want to target this value

我一直在尝试几种不同的方法,每种方法都有不同的结果。

$Assembly = 'C:\path\to\AssemblyInfo.cs'
$regex = '(?<!\/\/ \[assembly:AssemblyVersion\(")(?<=AssemblyVersion\(")[^"]*'
$regex2 = ('`n\[assembly: AssemblyVersion\("'+$CurrentVersion+'"\)\]')

尝试001

(GC $Assembly) |
ForEach-Object { $_.Replace($CurrentVersion, $NewVersion) } |
Set-Content $Assembly

这是一个明显的失败。它最终会替换&#39; 1.0。*&#39;

的两个实例

尝试002

GC $Assembly | 
Select-String -Pattern '^\[assembly' -AllMatches | 
ForEach-Object { $_.Replace($CurrentVersion, $NewVersion) } |
Set-Content $Assembly

以不兼容的命令问题结束......

尝试003

(GC $Assembly) | ForEAch-Object { 
    If ( $_ -MATCH $CurrentVersion ) {
        ForEach ($Line in $_) {
            $_.Replace($CurrentVersion, $NewVersion)
        }
    }
 } |
 Set-Content $Assembly

这最终删除了包含//作为起始字符的所有行......这不是我想要的......

尝试004

GC $Assembly |
ForEach-Object {
    $_.Replace($regex2, ('[assembly: AssemblyVersion("'+$NewVersion+'")]'))
} |
Set-Content $Assembly

我收到错误消息说该文件正在使用中......但由于我无法找到任何使用该文件的内容,因此没有任何意义...

我也尝试了其他几条路径,以上4的大部分变体都希望达到我的目标。甚至可以使用上面提供的正则表达式线来定位线,并尝试使用它的变体

问题

使用PowerShell,我如何只替换目标行的行/值(忽略以//开头的行),但在保存内容时仍保留文件中的所有行?

1 个答案:

答案 0 :(得分:3)

您正在尝试使用正则表达式模式,但继续使用不支持它的字符串方法.Replace()。您应该使用-replace运算符。这将解决您的部分问题。

看起来你只想更换除了程序集信息之外没有任何其他内容的行。

$path = "C:\temp\test.txt"
$newVersion = "1.0.0.1"
$pattern = '^\s*?\[assembly: AssemblyVersion\("(.*)"\)\]'
(Get-Content $path) | ForEach-Object{
    if($_ -match $pattern){
        # We have found the matching line
        '[assembly: AssemblyVersion("{0}")]' -f $newVersion
    } else {
        # Output line as is
        $_
    }
} | Set-Content $path

这将是一个冗长而简单的方式来做你想要的事情。只有当装配线位于具有可选空格的行的开头时才会匹配。

我希望模式'^[assembly: AssemblyVersion\("(.*)"\)\]'能够正常工作,因为无论如何它应该出现在行的开头。

This comes from another answer about almost this exact problem除了现在有更多的匹配可能性。此外,您将看到我的正则表达式模式隔离当前版本,以防您需要。如果是这种情况,请查看链接的问题。

您可以将其与其他选项结合使用,但如果您提前知道要使用的版本,那么替换也非常简单。

$newVersion = "1.6.5.6"
(Get-Content $path -Raw) -replace '(?m)^\[assembly: AssemblyVersion\("(.*)"\)\]', ('[assembly: AssemblyFileVersion("{0}")]' -f $newVersion)  | Set-Content $path

只要模式位于文件中行的开头,它就会将文件作为一个字符串读取并执行替换。 (?m)让我们将行锚^的开头视为在文本行的开头起作用的东西。不只是整个字符串的开头。