web-dev-qa-db-ja.com

ファイル内のすべての文字列をPowerShellで置き換える方法を教えてください。

PowerShellを使用して、特定のファイル内のすべての正確な[MYID]MyValueに置き換えます。最も簡単な方法は何ですか?

247
amateur

使用(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
370
Loïc MICHEL
(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 |どこで….

86
Shay Levy

次の例に示すように、.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 そこにメソッドをステップスルーするための鍵。

72
rominator007

上記のものは "One File"に対してのみ動作しますが、フォルダ内の複数のファイルに対してこれを実行することもできます。

Get-ChildItem 'C:yourfile*.xml' -Recurse | ForEach {
     (Get-Content $_ | ForEach  { $_ -replace '[MYID]', 'MyValue' }) |
     Set-Content $_
}
19
John V Hobbs Jr

あなたはこのようなことを試すことができます:

$path = "C:\testFile.txt"
$Word = "searchword"
$replacement = "ReplacementText"
$text = get-content $path 
$newText = $text -replace $Word,$replacement
$newText > $path
10
Richard

これは私が使用しているものですが、大きなテキストファイルでは遅くなります。

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'
0
js2010

これは私にとってPowerShellの現在の作業ディレクトリを使用してうまくいきました。 FullNameプロパティを使用する必要があります。そうしないと、PowerShellバージョン5では機能しません。すべてのCSPROJファイルで、ターゲット.NETフレームワークのバージョンを変更する必要がありました。

gci -Recurse -Filter *.csproj |
% { (get-content "$($_.FullName)")
.Replace('<TargetFramework>net47</TargetFramework>', '<TargetFramework>net462</TargetFramework>') |
 Set-Content "$($_.FullName)"}
0

特定のファイル名のすべてのインスタンスで特定の行を変更する必要があるため、少し古くて違います。

また、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バージョンで私に最適なものです。

Major.Minor.Build.Revision

5.1.16299.98

0
Kalin Tashev

@ rominator007へのクレジット

私はそれを関数にラップしました(あなたが再びそれを使いたいと思うかもしれないので)

function Replace-AllStringsInFile($SearchString,$ReplaceString,$FullPathToFile)
{
    $content = [System.IO.File]::ReadAllText("$FullPathToFile").Replace("$SearchString","$ReplaceString")
    [System.IO.File]::WriteAllText("$FullPathToFile", $content)
}

注:これは大文字と小文字を区別しません!!!!!

この記事を参照してください: String.Replace大文字と小文字の区別を無視

0
Kolob Canyon