web-dev-qa-db-ja.com

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

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

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
146
dahlbyk

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
23
TroyBramley

PowerShellのバージョン3を使用すると、置換呼び出しを連結できます。

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

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を削除するだけです。

8
George Howarth

パイプライン化されたワンライナーの3番目のオプションは、-replacesをネストすることです。

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

そして:

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

これにより、実行順序が保持され、読みやすく、パイプラインにきちんと収まります。明示的な制御、自己文書化などのために括弧を使用することを好みます。括弧はなくても機能しますが、それをどこまで信頼しますか?

-Replaceは比較演算子であり、オブジェクトを受け入れ、おそらく変更されたオブジェクトを返します。これが、上記のようにスタックまたはネストできる理由です。

見てください:

help about_operators
6
Haakon Dahl