字符串匹配后替换下两行

时间:2021-03-03 16:51:48

标签: regex windows powershell powershell-3.0 powershell-4.0

我目前正在编写一个脚本,该脚本应根据用户的选择替换文件中匹配字符串后的两行。

我要编辑的文件如下所示:

[default]
string_a=sadasdasdas
string_b=dasdasdasdas

[profile1]
string_a=xxxxxx
string_b=xsaassaasas

[profile2]
string_a=yyyyyyy
string_b=yaayayayaya

我想总是在 [default] 之后覆盖 string_a 和 string_b。 请注意,[default] 也可能位于文件的最底部,因此我不能只计算行数并进行静态操作。

用户可以选择(在这种情况下)配置文件 1 和配置文件 2。在他选择配置文件 2 之后,配置文件 2 的 string_a 和 string_b 应该替换为默认的 string_a 和 string_b。

我现在的代码是这样的:

$filePath = './credentials'
$fileContent =  Get-Content $filePath

$profiles = [regex]::Matches($fileContent, '\[(.*?)\]') |ForEach-Object { $_.Groups[1].Value }

Write-Host "Following profiles found: "
for ($i=0; $i -lt $profiles.length; $i++){
    Write-Host $i"." $profiles[$i] 
}

$userInput = Read-Host "Which profile set to default? "
Write-Host $profiles[$userInput]

$fileContent | Select-String $profiles[$userInput] -Context 1,2 | ForEach-Object {
    $stringA =  $_.Context.PostContext[0]
    $stringB =  $_.Context.PostContext[1]

    #At this point I have access to the both string´s I want to replace the string´s of the default profile

    # I could do this, but then I still have the old lines in the file...
    # So the following code is not an option.
    $NewContent = Get-Content -Path $filePath |
    ForEach-Object {
        # Output the existing line to pipeline in any case
        $_

        # If line matches regex
        if($_ -match ('^' + [regex]::Escape('[default]')))
        {
            # Add output additional line
            $stringA
            $stringB
        }
    }

    # Write content of $NewContent varibale back to file
    $NewContent | Out-File -FilePath $filePath -Encoding Default -Force
}

示例输出文件,以防用户选择 profile1 作为新的默认值

[default]
string_a=xxxxxx
string_b=xsaassaasas

[profile1]
string_a=xxxxxx
string_b=xsaassaasas

[profile2]
string_a=yyyyyyy
string_b=yaayayayaya

希望这不是显而易见的,但由于它是我的第一个真正的 powershell 脚本,我还没有找到解决我的问题的方法。

任何帮助都会很棒!

谢谢

1 个答案:

答案 0 :(得分:0)

示例:

# This is sample data
$lines = @(@'
[default]
string_a=sadasdasdas
string_b=dasdasdasdas

[profile1]
string_a=xxxxxx
string_b=xsaassaasas

[profile2]
string_a=yyyyyyy
string_b=yaayayayaya
'@ -split "`r`n")

# In real world use: 
# $encoding = [System.Text.Encoding]::ASCII
# $lines = [System.IO.File]::ReadAllLines($path, $encoding)

#Read file
$lines = $lines | ForEach-Object { $_.Trim()} # Trim spaces
$sections = @{}
$currentSection = $null
$hasErrors = $false
$lines | ForEach-Object {
    if ([String]::IsNullOrWhiteSpace($_)) {
        #ignore
    } elseif ($_.StartsWith('[') -and $_.EndsWith(']') ) {
        $currentSection = $_.Substring($_.IndexOf('[') + 1, $_.LastIndexOf(']') - 1)
        $sections[$currentSection] = @{}
    } elseif ($sections.ContainsKey($currentSection)) {
        $PVPair = [String[]]$_.Split('=',2)
        if ($PVPair.Count -eq 2) {
            $sections[$currentSection][$PVPair[0]] = $PVPair[1]
        } else {
            Write-Warning -Message "Wrong line format [$($_)]"
            $hasErrors = $true
        }
    } else {
        Write-Warning -Message "Unexpected behaviour on section $currentSection, line $($_)"
        $hasErrors = $true
    }
}

if ($hasErrors) {
    Write-Error -Message 'Errors occured'
    return
}

# Choice
$choice = $null
$choiceVariants = @($sections.Keys | Where-Object { $_ -ne 'default' })
while ($choiceVariants -notcontains $choice) {
    Write-Host "Choose between $($choiceVariants -join ',')"
    $choice = $choiceVariants | Out-GridView -Title 'Choose variant' -OutputMode Single 
    #Alternative: $choice = Read-Host -Prompt "Your choice"
}

Write-Host -ForegroundColor Yellow "You choose $($choice)"

# Change
$sections[$choice]['string_a'] = $sections['default']['string_a']
$sections[$choice]['string_b'] = 'newXSAA'

# Output
$outputLines = $sections.Keys | ForEach-Object {
        $sectionName = $_
        Write-Output "[$sectionName]"
        $sections[$sectionName].Keys | ForEach-Object {
            Write-Output "$_=$($sections[$sectionName][$_])"
        }
    }

# This is sample output
$outputLines | % { Write-Host $_ -f Magenta }

# In Real world:
# [System.IO.File]::WriteAllLines($path, $outputLines, $encoding)
相关问题