PowerShell을 사용하여 파일에서 여러 문자열을 바꾸는 방법


107

구성 파일을 사용자 지정하기위한 스크립트를 작성 중입니다. 이 파일 내에서 여러 문자열 인스턴스를 바꾸고 싶고 PowerShell을 사용하여 작업을 수행했습니다.

단일 교체에는 잘 작동하지만 여러 교체를 수행하는 것은 매번 전체 파일을 다시 구문 분석해야하고이 파일은 매우 크기 때문에 매우 느립니다. 스크립트는 다음과 같습니다.

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'
(Get-Content $original_file) | Foreach-Object {
    $_ -replace 'something1', 'something1new'
    } | Set-Content $destination_file

나는 이것과 같은 것을 원하지만 그것을 작성하는 방법을 모릅니다.

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'
(Get-Content $original_file) | Foreach-Object {
    $_ -replace 'something1', 'something1aa'
    $_ -replace 'something2', 'something2bb'
    $_ -replace 'something3', 'something3cc'
    $_ -replace 'something4', 'something4dd'
    $_ -replace 'something5', 'something5dsf'
    $_ -replace 'something6', 'something6dfsfds'
    } | Set-Content $destination_file

답변:


167

한 가지 옵션은 -replace작업을 함께 연결하는 것입니다. `각 라인의 끝에 다음 행에 식을 구문 분석을 계속 PowerShell을 일으키는 원인이되는 줄 바꿈을 탈출 :

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'
(Get-Content $original_file) | Foreach-Object {
    $_ -replace 'something1', 'something1aa' `
       -replace 'something2', 'something2bb' `
       -replace 'something3', 'something3cc' `
       -replace 'something4', 'something4dd' `
       -replace 'something5', 'something5dsf' `
       -replace 'something6', 'something6dfsfds'
    } | Set-Content $destination_file

또 다른 옵션은 중간 변수를 할당하는 것입니다.

$x = $_ -replace 'something1', 'something1aa'
$x = $x -replace 'something2', 'something2bb'
...
$x

$ original_file == $ destination_file 수 있습니까? 내 소스와 동일한 파일을 수정하고 있습니까?
cquadrini 2013 년

PowerShell cmdlet이 입력 / 출력을 스트리밍하는 방식 때문에 동일한 파이프 라인에서 동일한 파일에 쓰는 것이 작동하지 않을 것이라고 생각합니다. 그러나 $c = Get-Content $original_file; $c | ... | Set-Content $original_file.
dahlbyk

원래 인코딩을 유지하지 않는 Set-Content 를 사용한 파일 인코딩에 문제가 있습니까? 예를 들어 UTF-8 또는 ANSI 인코딩.
Kiquenet 2015 년

1
그래 PowerShell은 ... 그렇게 도움이되지 않습니다. 인코딩을 직접 감지해야합니다. 예 : github.com/dahlbyk/posh-git/blob/…
dahlbyk

24

George Howarth의 게시물이 둘 이상의 대체물로 제대로 작동하도록하려면 중단을 제거하고 출력을 변수 ($ line)에 할당 한 다음 변수를 출력해야합니다.

$lookupTable = @{
    'something1' = 'something1aa'
    'something2' = 'something2bb'
    'something3' = 'something3cc'
    'something4' = 'something4dd'
    'something5' = 'something5dsf'
    'something6' = 'something6dfsfds'
}

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'

Get-Content -Path $original_file | ForEach-Object {
    $line = $_

    $lookupTable.GetEnumerator() | ForEach-Object {
        if ($line -match $_.Key)
        {
            $line = $line -replace $_.Key, $_.Value
        }
    }
   $line
} | Set-Content -Path $destination_file

이것은 내가 지금까지 본 것 중 최고의 접근 방식입니다. 유일한 문제는 동일한 소스 / 대상 파일 경로를 사용하기 위해 먼저 전체 파일 내용을 변수로 읽어야한다는 것입니다.
angularsen

이것이 가장 좋은 대답처럼 보이지만 잘못 일치하는 이상한 동작을 보았습니다. 즉, 16 진수 값이 문자열 (0x0, 0x1, 0x100, 0x10000) 인 해시 테이블이 있고 0x10000이 0x1과 일치하는 경우입니다.
Lorek

13

PowerShell 버전 3을 사용하면 replace 호출을 함께 연결할 수 있습니다.

 (Get-Content $sourceFile) | ForEach-Object {
    $_.replace('something1', 'something1').replace('somethingElse1', 'somethingElse2')
 } | Set-Content $destinationFile

작품 미세 + 유창한 맛
hdoghmen

10

한 줄에 'something1'또는 'something2'등을 하나만 가질 수 있다고 가정하면 조회 테이블을 사용할 수 있습니다.

$lookupTable = @{
    'something1' = 'something1aa'
    'something2' = 'something2bb'
    'something3' = 'something3cc'
    'something4' = 'something4dd'
    'something5' = 'something5dsf'
    'something6' = 'something6dfsfds'
}

$original_file = 'path\filename.abc'
$destination_file =  'path\filename.abc.new'

Get-Content -Path $original_file | ForEach-Object {
    $line = $_

    $lookupTable.GetEnumerator() | ForEach-Object {
        if ($line -match $_.Key)
        {
            $line -replace $_.Key, $_.Value
            break
        }
    }
} | Set-Content -Path $destination_file

둘 이상을 가질 수있는 경우 문 break에서 제거하십시오 if.


TroyBramley는 마지막 줄 바로 앞에 $ line을 추가하여 변경 사항이없는 줄을 작성했습니다. 괜찮아. 제 경우에는 교체가 필요한 모든 라인 만 변경했습니다.
cliffclof

8

파이프 라인 된 한 줄짜리 세 번째 옵션은 -replaces를 중첩하는 것입니다.

PS> ("ABC" -replace "B","C") -replace "C","D"
ADD

과:

PS> ("ABC" -replace "C","D") -replace "B","C"
ACD

이것은 실행 순서를 유지하고 읽기 쉽고 파이프 라인에 깔끔하게 맞습니다. 명시 적 제어, 자기 문서화 등에 괄호를 사용하는 것을 선호합니다. 괄호 없이도 작동하지만 얼마나 신뢰하십니까?

-Replace는 객체를 받아들이고 아마도 수정 된 객체를 반환하는 비교 연산자입니다. 이것이 위와 같이 스택하거나 중첩 할 수있는 이유입니다.

참조하십시오 :

help about_operators
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.