Powershell函数用于替换或添加文本文件中的行

时间:2013-03-27 15:31:13

标签: regex powershell replace append

我正在研究修改配置文件的powershell脚本。我有这样的文件:

#####################################################
# comment about logentrytimeout
#####################################################
Logentrytimeout= 1800

谁应该是这样的:

#####################################################
# comment about logentrytimeout
#####################################################
Logentrytimeout= 180
disablepostprocessing = 1
segmentstarttimeout = 180

如果存在密钥集(Logentrytimeout),只需将其更新为给定值即可。忽略注释,其中提到了键(以#开头的行)。密钥不区分大小写。

如果未设置密钥(disablepostprocessing和segmentstarttimeout),请将密钥和值附加到文件。到目前为止我的功能是这样的:

function setConfig( $file, $key, $value )
{
  (Get-Content $file) |
  Foreach-Object {$_ -replace "^"+$key+".=.+$", $key + " = " + $value } |
  Set-Content $file
}

setConfig divider.conf "Logentrytimeout" "180"
setConfig divider.conf "disablepostprocessing" "1"
setConfig divider.conf "segmentstarttimeout" "180"
  • 正确的正则表达式是什么?
  • 如何检查是否有更换?
  • 如果没有替换:我怎样才能将$ key +“=”+ $ value附加到文件中?

6 个答案:

答案 0 :(得分:13)

假设您要替换的$key始终位于一行的开头,并且它不包含特殊的正则表达式字符

function setConfig( $file, $key, $value ) {
    $content = Get-Content $file
    if ( $content -match "^$key\s*=" ) {
        $content -replace "^$key\s*=.*", "$key = $value" |
        Set-Content $file     
    } else {
        Add-Content $file "$key = $value"
    }
}

setConfig "divider.conf" "Logentrytimeout" "180" 

如果没有替换$key = $value将附加到文件中。

答案 1 :(得分:3)

如果需要,可以使用一些参数化和详细输出更新上述函数的版本。

   Function Set-FileConfigurationValue()
{
    [CmdletBinding(PositionalBinding=$false)]   
    param(
        [Parameter(Mandatory)][string][ValidateScript({Test-Path $_})] $Path,
        [Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Key,
        [Parameter(Mandatory)][string][ValidateNotNullOrEmpty()] $Value,
        [Switch] $ReplaceExistingValue,
        [Switch] $ReplaceOnly
    )

    $content = Get-Content -Path $Path
    $regreplace = $("(?<=$Key).*?=.*")
    $regValue = $("=" + $Value)
    if (([regex]::Match((Get-Content $Path),$regreplace)).success)
    {
        If ($ReplaceExistingValue)
        {
            Write-Verbose "Replacing configuration Key ""$Key"" in configuration file ""$Path"" with Value ""$Value"""
            (Get-Content -Path $Path) | Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue) } | Set-Content $Path
        }
        else
        {
            Write-Warning "Key ""$Key"" found in configuration file ""$Path"". To replace this Value specify parameter ""ReplaceExistingValue"""
        }
    } 
    elseif (-not $ReplaceOnly) 
    {    
        Write-Verbose "Adding configuration Key ""$Key"" to configuration file ""$Path"" using Value ""$Value"""
        Add-Content -Path $Path -Value $("`n" + $Key + "=" + $Value)       
    }
    else
    {
        Write-Warning "Key ""$Key"" not found in configuration file ""$Path"" and parameter ""ReplaceOnly"" has been specified therefore no work done"
    }
}

答案 2 :(得分:2)

我会这样做:

function setConfig( $file, $key, $value )
{
  $regex = '^' + [regex]::escape($key) + '\s*=.+'
  $replace = "$key = $value"
  $old = get-content $file
  $new = $old -replace $regex,$replace 

  if (compare-object $old $new)
    {  
      Write-Host (compare-object $old $new |  ft -auto | out-string) -ForegroundColor Yellow
      $new | set-content $file
    }

    else {
           $replace | add-content $file
           Write-Host "$replace added to $file" -ForegroundColor Cyan
         }

}

编辑:添加了一个替换铃,一个不匹配的口哨。

答案 3 :(得分:1)

将功能更改为:

function Set-Config( $file, $key, $value )
{
    $regreplace = $("(?<=$key).*?=.*")
    $regvalue = $(" = " + $value)
    if (([regex]::Match((Get-Content $file),$regreplace)).success) {
        (Get-Content $file) `
            |Foreach-Object { [regex]::Replace($_,$regreplace,$regvalue)
         } | Set-Content $file
    } else {
        Add-Content -Path $file -Value $("`n" + $key + " = " + $value)          
    }
}

然后,当您调用该函数时,请使用以下格式:

Set-Config -file "divider.conf" -key "Logentrytimeout" -value "180"

编辑:如果不存在,我忘记了添加该行的要求。这将检查$key,如果存在,则会将其值设置为$value。如果它不存在,它会将$key = $value添加到文件的末尾。我还将该函数重命名为与power shell命名约定更加一致。

答案 4 :(得分:0)

@CarlR功能适用于PowerShell版本3.这适用于 PowerShell版本2

编辑:更改正则表达式以修复Set-FileConfigurationValue上的两个错误:

  1. 如果你有这样的一行:

    ; This is a Black line

    你试着这样做:

    Set-FileConfigurationValue $configFile "Black" 20 -ReplaceExistingValue

    您收到一条关于“替换”的消息,但没有任何反应。

  2. 如果您有两条这样的行:

    filesTmp = 50
    TMP = 50

    你试着这样做:

    Set-FileConfigurationValue $configFile "Tmp" 20 -ReplaceExistingValue

    你改变了两行!

    filesTmp = 20 TMP = 20

  3. 这是最终版本:

    Function Set-FileConfigurationValue()
    {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$True)]
            [ValidateScript({Test-Path $_})]
            [string] $Path,
            [Parameter(Mandatory=$True)]
            [ValidateNotNullOrEmpty()]
            [string] $Key,
            [Parameter(Mandatory=$True)]
            [ValidateNotNullOrEmpty()] 
            [string]$Value,
            [Switch] $ReplaceExistingValue,
            [Switch] $ReplaceOnly
        )
    
        $regmatch= $("^($Key\s*=\s*)(.*)")
        $regreplace=$('${1}'+$Value)
    
        if ((Get-Content $Path) -match $regmatch)
        {
            If ($ReplaceExistingValue)
            {
                Write-Verbose "Replacing configuration Key ""$Key"" in configuration file ""$Path"" with Value ""$Value"""
                (Get-Content -Path $Path) | ForEach-Object { $_ -replace $regmatch,$regreplace } | Set-Content $Path
            }
            else
            {
                Write-Warning "Key ""$Key"" found in configuration file ""$Path"". To replace this Value specify parameter ""ReplaceExistingValue"""
            }
        } 
        elseif (-not $ReplaceOnly) 
        {    
            Write-Verbose "Adding configuration Key ""$Key"" to configuration file ""$Path"" using Value ""$Value"""
            Add-Content -Path $Path -Value $("`n" + $Key + "=" + $Value)       
        }
        else
        {
            Write-Warning "Key ""$Key"" not found in configuration file ""$Path"" and parameter ""ReplaceOnly"" has been specified therefore no work done"
        }
    }
    

    我还添加了一个从配置文件中读取的功能

    Function Get-FileConfigurationValue()
    {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$True)]
            [ValidateScript({Test-Path $_})]
            [string] $Path,
            [Parameter(Mandatory=$True)]
            [ValidateNotNullOrEmpty()]
            [string] $Key,
            [Parameter(Mandatory=$False)]
            [ValidateNotNullOrEmpty()] 
            [string]$Default=""
        )
    
        # Don't have spaces before key. 
        # To allow spaces, use "$Key\s*=\s*(.*)"
        $regKey = $("^$Key\s*=\s*(.*)")
    
        # Get only last time 
        $Value = Get-Content -Path $Path | Where {$_ -match $regKey} | Select-Object -last 1 | ForEach-Object { $matches[1] }
        if(!$Value) { $Value=$Default }
    
        Return $Value
    }  
    

答案 5 :(得分:0)

function sed($filespec, $search, $replace)
{
    foreach ($file in gci -Recurse $filespec | ? { Select-String $search $_ -Quiet } )
    { 
    (gc $file) | 
     ForEach-Object {$_ -replace $search, $replace } | 
     Set-Content $file
    }
}

用法:

sed ".\*.config" "intranet-" "intranetsvcs-"