[powershell] 특정 확장자를 가진 모든 파일을 찾고 바꾸기위한 PowerShell 스크립트

Windows Server 2008에 다음과 같이 중첩 된 여러 구성 파일이 있습니다.

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config

내 구성에서 다음과 같은 문자열 교체를 수행해야합니다.

<add key="Environment" value="Dev"/>

될 것입니다:

<add key="Environment" value="Demo"/>

일괄 스크립팅을 사용하는 것에 대해 생각했지만이 작업을 수행하는 좋은 방법이 없었고 PowerShell 스크립팅을 사용하면 쉽게 수행 할 수 있다고 들었습니다. 찾기 / 바꾸기의 예를 찾았지만 내 C : \ Projects 디렉터리 내의 모든 폴더를 탐색하고 ‘.config’확장자로 끝나는 파일을 찾는 방법을 찾고있었습니다. 하나를 찾으면 내 문자열 값을 바꾸고 싶습니다.

이 작업을 수행하는 방법을 찾을 수있는 좋은 리소스 또는 통찰력을 제공 할 수있는 PowerShell 전문가가 있습니까?



답변

여기 내 머리 꼭대기에서 첫 번째 시도.

$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
    (Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace "Dev", "Demo" } |
    Set-Content $file.PSPath
}


답변

PowerShell은 좋은 선택입니다.;) 주어진 디렉토리에서 파일을 열거하고 읽고 처리하는 것은 매우 쉽습니다.

스크립트는 다음과 같습니다.

Get-ChildItem C:\Projects *.config -recurse |
    Foreach-Object {
        $c = ($_ | Get-Content)
        $c = $c -replace '<add key="Environment" value="Dev"/>','<add key="Environment" value="Demo"/>'
        [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
    }

나는 당신이 읽을 수 있도록 코드를 더 많은 줄로 나누었습니다. 대신 Set-Content를 사용할 수 [IO.File]::WriteAllText있지만 끝에 새 줄이 추가됩니다. WriteAllText당신 과 함께 그것을 피할 수 있습니다.

그렇지 않으면 코드는 다음과 같습니다 $c | Set-Content $_.FullName..


답변

이 접근 방식은 잘 작동합니다.

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_
}
  • “이전”및 “새”를 해당 값으로 변경하거나 변수를 사용합니다.
  • 괄호를 잊지 마십시오. 그렇지 않으면 액세스 오류가 발생합니다.

답변

xml과 xpath를 사용합니다.

dir C:\Projects\project_*\project*.config -recurse | foreach-object{
   $wc = [xml](Get-Content $_.fullname)
   $wc.SelectNodes("//add[@key='Environment'][@value='Dev']") | Foreach-Object {$_.value = 'Demo'}
   $wc.Save($_.fullname)
}


답변

이 powershell 예제는 폴더 및 하위 폴더에서 “\ foo \”문자열의 모든 인스턴스를 찾고 “\ foo \”를 “\ bar \”로 바꾸며 문자열 “\ foo \를 포함하지 않는 파일을 다시 쓰지 않습니다. “이렇게하면 문자열이 발견되지 않은 마지막 업데이트 날짜 / 시간 스탬프 파일을 파괴하지 않습니다.

Get-ChildItem  -Path C:\YOUR_ROOT_PATH\*.* -recurse
 | ForEach {If (Get-Content $_.FullName | Select-String -Pattern '\\foo\\')
           {(Get-Content $_ | ForEach {$_ -replace '\\foo\\', '\bar\'}) | Set-Content $_ }
           }


답변

@Artyom의 의견이 유용하다는 것을 알았지 만 불행히도 그는 답변을 게시하지 않았습니다.

이것은 내 생각에 가장 좋은 버전의 짧은 버전입니다.

ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}


답변

파일의 텍스트를 대체하는 작은 도우미 함수를 작성했습니다.

function Replace-TextInFile
{
    Param(
        [string]$FilePath,
        [string]$Pattern,
        [string]$Replacement
    )

    [System.IO.File]::WriteAllText(
        $FilePath,
        ([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement)
    )
}

예:

Get-ChildItem . *.config -rec | ForEach-Object {
    Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new'
}