回答:
使用(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)
が必要であることに注意してください:
括弧がない場合、コンテンツは一度に1行ずつ読み取られ、同じファイルに書き込もうとするout-fileまたはset-contentに到達するまでパイプラインを流れますが、get-contentによってすでに開かれているため、エラー。括弧により、コンテンツの読み取り操作が1回実行されます(オープン、読み取り、クローズ)。すべての行が読み取られたときにのみ、それらは一度に1つずつパイプ処理され、パイプラインの最後のコマンドに到達すると、ファイルに書き込むことができます。$ content = contentと同じです。$ content | どこ ...
Set-Content
代わりにを使用すると、「プロセスはファイル '123.csv'にアクセスできません。別のプロセスによって使用されているためです。」のOut-File
ような警告が表示されます。。
Get-Content
括弧内のそれが動作します。かっこが必要な理由を回答で説明できますか?それはより安全Out-File
であるSet-Content
ため、私はまだ置き換えます。かっこを忘れた場合にターゲットファイルが消去されるのを防ぎます。
Set-Content
代わりにを使用するOut-File
方がはるかに優れており、より安全なソリューションです。申し訳ありませんが、反対票を投じる必要があります。
次の例に示すように、.NETのFileクラスとその静的メソッドの使用を好みます。
$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
ですか?
上記のものは「1つのファイル」に対してのみ実行されますが、フォルダ内の複数のファイルに対しても実行できます。
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'"
複数のファイルの文字列を置き換える必要がある場合:
ここに掲載されているさまざまなメソッドは、完了までにかかる時間に関して大幅に異なる場合があることに注意してください。私にとって、私は定期的に多数の小さなファイルを持っています。最もパフォーマンスの高いものをテストするために、5.52 GB(5,933,604,999バイト)のXMLを40,693の個別のファイルに抽出し、ここで見つけた3つの回答を実行しました。
## 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.Replace ignoring ignore case
これは、PowerShellの現在の作業ディレクトリを使用して動作しました。FullName
プロパティを使用する必要があります。そうしないと、PowerShellバージョン5では機能しませんCSPROJ
。すべてのファイルで、ターゲットの.NET Frameworkバージョンを変更する必要がありました。
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
、この中で示唆したように、ファイルを空にしません。