답변:
사용 (V3 버전) :
(Get-Content c:\temp\test.txt).replace('[MYID]', 'MyValue') | Set-Content c:\temp\test.txt
또는 V2의 경우 :
(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt
(Get-Content file.txt) |
Foreach-Object {$_ -replace '\[MYID\]','MyValue'} |
Out-File file.txt
괄호 (Get-Content file.txt)
는 다음과 같습니다.
괄호가 없으면 내용이 한 번에 한 줄씩 읽혀지고 파일 또는 세트 내용에 도달 할 때까지 파이프 라인을 따라 내려갑니다. 동일한 파일에 쓰려고 시도하지만 get-content에 의해 이미 열려 있고 오류. 괄호로 인해 콘텐츠 읽기 작업이 한 번만 수행됩니다 (열기, 읽기 및 닫기). 그런 다음에 만 모든 행을 읽을 때 한 번에 하나씩 파이프되고 파이프 라인의 마지막 명령에 도달하면 파일에 쓸 수 있습니다. $ content = content와 동일합니다. $ content | 어디 ...
Set-Content
대신 사용하면 "다른 프로세스에서 '123.csv'파일을 사용 중이기 때문에 프로세스가 파일에 액세스 할 수 없습니다."Out-File
와 같은 경고가 표시 됩니다. .
Get-Content
괄호 안에 그것을 작동합니다. 괄호가 필요한 이유를 답변에 설명해 주시겠습니까? 나는 아직도 대체 할 Out-File
로 Set-Content
는 더 안전하기 때문에; 괄호를 잊어 버린 경우 대상 파일을 지우는 것을 방지합니다.
Set-Content
대신에 사용 하는 Out-File
것이 훨씬 더 좋고 안전한 솔루션입니다. 공감해야합니다.
다음 예제에서 볼 수 있듯이 File 클래스의 .NET과 정적 메서드를 사용하는 것이 좋습니다.
$content = [System.IO.File]::ReadAllText("c:\bla.txt").Replace("[MYID]","MyValue")
[System.IO.File]::WriteAllText("c:\bla.txt", $content)
이것은 Get-Content 와 같이 String-array 대신 단일 String으로 작업 할 수 있다는 이점이 있습니다 . 또한 대부분의 시간을 신경 쓸 필요없이 파일 인코딩 (UTF-8 BOM 등)을 처리합니다.
또한 메서드는 Get-Content를 사용하고 Set-Content로 파이프하는 알고리즘과 달리 줄 끝 (사용할 수있는 Unix 줄 끝)을 엉망으로 만들지 않습니다. .
그래서 나를 위해 : 몇 년 동안 깰 수있는 것들이 적습니다.
.NET 클래스를 사용할 때 잘 알려진 점은 PowerShell 창에서 "[System.IO.File] ::"을 입력하면 Tab키를 눌러 방법을 단계별로 수행 할 수 있다는 것입니다.
[System.IO.File] | gm
C:\Windows\System32\WindowsPowerShell\v1.0
합니까?
위의 파일은 "하나의 파일"에 대해서만 실행되지만 폴더 내의 여러 파일에 대해서도 실행할 수 있습니다.
Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '[MYID]', 'MyValue' }) |
Set-Content $_
}
foreach
이것을 할 수 있습니다Get-ChildItem 'C:\folder\file*.xml' -Recurse | ForEach { (Get-Content $_).Replace('[MYID]', 'MyValue') | Set-Content $_ }
foreach
Get-Content가 예상치 못한 작업을 수행 하기 때문에 inner가 필요합니다 . 각 문자열이 파일의 한 줄인 문자열 배열을 반환합니다. 실행중인 스크립트와 다른 위치에있는 디렉토리 (및 하위 디렉토리)를 반복하는 경우 다음과 같은 것을 원할 것입니다 : 수정하려는 파일이 들어있는 디렉토리는 Get-ChildItem $Directory -File -Recurse | ForEach { (Get-Content $_.FullName) | ForEach { $_ -replace '[MYID]', 'MyValue' } | Set-Content $_.FullName }
어디에 있습니까 $Directory
?
이것이 내가 사용하는 것이지만 큰 텍스트 파일에서는 느립니다.
get-content $pathToFile | % { $_ -replace $stringToReplace, $replaceWith } | set-content $pathToFile
큰 텍스트 파일에서 문자열을 바꾸고 속도가 중요한 경우 System.IO.StreamReader 및 System.IO.StreamWriter 사용을 살펴보십시오 .
try
{
$reader = [System.IO.StreamReader] $pathToFile
$data = $reader.ReadToEnd()
$reader.close()
}
finally
{
if ($reader -ne $null)
{
$reader.dispose()
}
}
$data = $data -replace $stringToReplace, $replaceWith
try
{
$writer = [System.IO.StreamWriter] $pathToFile
$writer.write($data)
$writer.close()
}
finally
{
if ($writer -ne $null)
{
$writer.dispose()
}
}
(위의 코드는 테스트되지 않았습니다.)
문서에서 텍스트를 바꾸는 데 StreamReader와 StreamWriter를 사용하는 더 우아한 방법이있을 수 있지만 좋은 출발점이 될 것입니다.
Payette의 Windows Powershell in Action 에서 조금 알려졌지만 놀랍도록 멋진 방법을 찾았습니다 . $ env : path와 비슷한 변수와 같은 파일을 참조 할 수 있지만 중괄호를 추가해야합니다.
${c:file.txt} = ${c:file.txt} -replace 'oldvalue','newvalue'
$myFile
됩니까?
$a = 'file.txt'; invoke-expression "`${c:$a} = `${c:$a} -replace 'oldvalue','newvalue'"
여러 파일에서 문자열을 교체해야하는 경우 :
여기에 게시 된 다른 방법은 완료하는 데 걸리는 시간과 크게 다를 수 있습니다. 나를 위해 정기적으로 많은 수의 작은 파일이 있습니다. 가장 성능이 좋은 것을 테스트하기 위해 40,693 개의 별도 파일에서 5.52GB (5,933,604,999 바이트)의 XML을 추출하고 여기에서 찾은 세 가지 답변을 실행했습니다.
## 5.52 GB (5,933,604,999 bytes) of XML files (40,693 files)
#### Test 1 - Plain Replace
$start = get-date
$xmls = (Get-ChildItem -Path "I:\TestseT\All_XML" -Recurse -Filter *.xml).FullName
foreach ($xml in $xmls)
{
(Get-Content $xml).replace("'", " ") | Set-Content $xml
}
$end = get-date
NEW-TIMESPAN –Start $Start –End $End
<#
TotalMinutes: 103.725113128333
#>
#### Test 2 - Replace with -Raw
$start = get-date
$xmls = (Get-ChildItem -Path "I:\TestseT\All_XML" -Recurse -Filter *.xml).FullName
foreach ($xml in $xmls)
{
(Get-Content $xml -Raw).replace("'", " ") | Set-Content $xml
}
$end = get-date
NEW-TIMESPAN –Start $Start –End $End
<#
TotalMinutes: 10.1600227983333
#>
#### Test 3 - .NET, System.IO
$start = get-date
$xmls = (Get-ChildItem -Path "I:\TestseT\All_XML" -Recurse -Filter *.xml).FullName
foreach ($xml in $xmls)
{
$txt = [System.IO.File]::ReadAllText("$xml").Replace("'"," ")
[System.IO.File]::WriteAllText("$xml", $txt)
}
$end = get-date
NEW-TIMESPAN –Start $Start –End $End
<#
TotalMinutes: 5.83619516833333
#>
@ rominator007에 신용
함수에 래핑했습니다 (다시 사용하고 싶을 수도 있기 때문에)
function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
$content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
[System.IO.File]::WriteAllText("$FullPathToFile", $content)
}
참고 : 이것은 대소 문자를 구분하지 않습니다 !!!!!
이 게시물을 참조하십시오 : String. 대소 문자를 무시 하십시오.
이것은 PowerShell에서 현재 작업 디렉토리를 사용하여 나를 위해 일했습니다. 이 FullName
속성 을 사용해야합니다. 그렇지 않으면 PowerShell 버전 5에서 작동하지 않습니다 CSPROJ
. 모든 파일 에서 대상 .NET 프레임 워크 버전을 변경해야했습니다 .
gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
Set-Content "$($_.FullName)"}
특정 파일 이름의 모든 인스턴스에서 특정 줄을 변경해야했기 때문에 조금 오래되었습니다.
또한 Set-Content
일관된 결과를 반환하지 않았으므로에 의지해야했습니다 Out-File
.
아래 코드 :
$FileName =''
$OldLine = ''
$NewLine = ''
$Drives = Get-PSDrive -PSProvider FileSystem
foreach ($Drive in $Drives) {
Push-Location $Drive.Root
Get-ChildItem -Filter "$FileName" -Recurse | ForEach {
(Get-Content $_.FullName).Replace($OldLine, $NewLine) | Out-File $_.FullName
}
Pop-Location
}
이것이이 PowerShell 버전에서 가장 효과적이었습니다.
주요 사소한 건물 개정
5.1.16299.98
Set-Content 명령에 대한 작은 수정. 검색된 문자열을 찾지 못하면 Set-Content
명령은 대상 파일을 비 웁니다 (비어 있음).
찾고있는 문자열이 존재하는지 먼저 확인할 수 있습니다. 그렇지 않으면 아무것도 교체되지 않습니다.
If (select-string -path "c:\Windows\System32\drivers\etc\hosts" -pattern "String to look for") `
{(Get-Content c:\Windows\System32\drivers\etc\hosts).replace('String to look for', 'String to replace with') | Set-Content c:\Windows\System32\drivers\etc\hosts}
Else{"Nothing happened"}
set-content test.txt "hello hello world hello world hello"
다음은 (get-content .\test.txt).Replace("something", "awesome") | set-content .\test.txt
이에 제안 파일을 비워하지 않습니다.