2013-03-27 15 views
5

Pracuję nad skryptem powershell, który modyfikuje pliki konfiguracyjne. Mam pliki tak:Funkcja Powershell do zamiany lub dodania wierszy w plikach tekstowych

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

który powinien wyglądać tak:

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

Jeśli istnieje klucz zestaw (Logentrytimeout), po prostu go zaktualizować do podanej wartości. Zignoruj ​​komentarze, gdzie wymieniono klucz (linie zaczynające się od #). Klucz nie uwzględnia wielkości liter.

Jeśli klucz nie jest ustawiony (czas nieaktywny i czas segmentu), należy dołączyć do pliku klucz i wartość. Moja funkcja do tej pory idzie tak:

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" 
  • Jaka jest poprawna regex?
  • Jak sprawdzić, czy nastąpiła wymiana?
  • Jeśli nie było wymiany: w jaki sposób mogę do tego pliku dołączyć klucz $ + + = = + wartość $?

Odpowiedz

13

Zakładając, że $key chcesz zastąpić jest zawsze na początku linii, i że nie zawiera znaki specjalne regex

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" 

Jeśli nie ma wymiana $key = $value będą dołączane do pliku.

2

Chciałbym to zrobić:

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 
     } 

} 

Edycja: dodano dzwon zastępczą, a nie zgadza się gwizdek.

1

zmienić funkcję do tego:

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)   
    } 
} 

Następnie podczas wywołania funkcji, należy użyć tego formatu:

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

Edit: Zapomniałem swoje wymagania dodawania linii jeśli nie istnieć. To sprawdzi, czy $key, jeśli istnieje, ustawi jego wartość na $value. Jeśli nie istnieje, doda koniec do $key = $value. Zmieniłem także nazwę tej funkcji, aby była bardziej zgodna z konwencjami nazewnictwa powłoki Power.

3

Zaktualizowana wersja powyższych funkcji z parametryzacją i szczegółowym wyjściem, jeśli jest to wymagane.

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" 
    } 
} 
0

@CarlR Działanie to dla PowerShell w wersji 3. To jest to samo dostosowany do PowerShell w wersji 2.

EDIT: Zmieniono wyrażenia regularnego naprawić dwa błędy na planie-FileConfigurationValue:

  1. Jeśli masz jedną linię:

    ; This is a Black line

    I spróbować zrobić:

    Set-FileConfigurationValue $configFile "Black" 20 -ReplaceExistingValue

    Otrzymujesz jedną wiadomość o "Replacing", ale nic się nie dzieje.

  2. Jeśli masz dwie linie takie jak:

    filesTmp = 50
    Tmp = 50

    I spróbować zrobić:

    Set-FileConfigurationValue $configFile "Tmp" 20 -ReplaceExistingValue

    dostaniesz dwie linie zmieniły !

    filesTmp = 20 Tmp = 20

To jest ostateczna wersja:

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" 
    } 
} 

Dodałem także funkcję do odczytu z pliku konfiguracyjnego

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 
} 
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 
    } 
} 

Użycie:

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