PowerShellを使用してファイル内の複数の文字列を置き換える方法


106

構成ファイルをカスタマイズするためのスクリプトを書いています。このファイル内の文字列の複数のインスタンスを置き換えたいので、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

1つのオプションは、-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コマンドレットが入力/出力をストリーミングする方法が原因で、同じパイプライン内の同じファイルに書き出すことができるとは思いません。ただし、のようなことができます$c = Get-Content $original_file; $c | ... | Set-Content $original_file
dahlbyk 2013年

元のエンコーディングを維持しないSet-Contentを使用したファイルエンコーディングについて問題がありますか?たとえば、UTF-8またはANSIエンコーディング。
Kiquenet、2015年

1
そうですね、PowerShellは...そのようには役に立ちません。自分でエンコーディングを検出する必要があります。たとえば、github.com
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、2016

13

PowerShellのバージョン3では、replace呼び出しを一緒にチェーンできます。

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

うまく機能+
滑らか

10

1行に1 つのみ、'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を追加して、変更のない行を記述しているのを確認しました。はい。私の場合、交換が必要なすべての行のみを変更しました。
クリフクロフ

8

パイプライン化されたワンライナーの3番目のオプションは、-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.