I am writing a script for customising a configuration file. I want to replace multiple instances of strings within this file, and I tried using PowerShell to do the job.
It works fine for a single replace, but doing multiple replaces is very slow because each time it has to parse the whole file again, and this file is very large. The script looks like this:
$original_file = 'path\filename.abc'
$destination_file = 'path\filename.abc.new'
(Get-Content $original_file) | Foreach-Object {
$_ -replace 'something1', 'something1new'
} | Set-Content $destination_file
I want something like this, but I don't know how to write it:
$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
This question is related to
powershell
replace
With version 3 of PowerShell you can chain the replace calls together:
(Get-Content $sourceFile) | ForEach-Object {
$_.replace('something1', 'something1').replace('somethingElse1', 'somethingElse2')
} | Set-Content $destinationFile
To get the post by George Howarth working properly with more than one replacement you need to remove the break, assign the output to a variable ($line) and then output the variable:
$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
A third option, for a pipelined one-liner is to nest the -replaces:
PS> ("ABC" -replace "B","C") -replace "C","D"
ADD
And:
PS> ("ABC" -replace "C","D") -replace "B","C"
ACD
This preserves execution order, is easy to read, and fits neatly into a pipeline. I prefer to use parentheses for explicit control, self-documentation, etc. It works without them, but how far do you trust that?
-Replace is a Comparison Operator, which accepts an object and returns a presumably modified object. This is why you can stack or nest them as shown above.
Please see:
help about_operators
Assuming you can only have one 'something1'
or 'something2'
, etc. per line, you can use a lookup table:
$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
If you can have more than one of those, just remove the break
in the if
statement.
Source: Stackoverflow.com