我正在编写一个用于自定义配置文件的脚本。我想在这个文件中替换多个字符串实例,我尝试使用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
答案 0 :(得分:140)
一种选择是将-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
答案 1 :(得分:22)
要获得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
答案 2 :(得分:10)
使用PowerShell的第3版,您可以将替换调用链接在一起:
(Get-Content $sourceFile) | ForEach-Object {
$_.replace('something1', 'something1').replace('somethingElse1', 'somethingElse2')
} | Set-Content $destinationFile
答案 3 :(得分:8)
假设每行只能有一个'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
。
答案 4 :(得分:5)
第三个选项,对于流水线单行,是嵌套-replaces:
PS> ("ABC" -replace "B","C") -replace "C","D"
ADD
和
PS> ("ABC" -replace "C","D") -replace "B","C"
ACD
这保留了执行顺序,易于阅读,并且非常适合管道。我更喜欢使用括号进行显式控制,自我记录等。没有它们可以工作,但你相信这有多远?
-Replace是一个比较运算符,它接受一个对象并返回一个推测修改过的对象。这就是您可以如上所示堆叠或嵌套它们的原因。
请参阅:
help about_operators
答案 5 :(得分:0)
只是一个通用的可重用解决方案:
function Replace-String {
[CmdletBinding()][OutputType([string])] param(
[Parameter(Mandatory = $True, ValueFromPipeLine = $True)]$InputObject,
[Parameter(Mandatory = $True, Position = 0)][Array]$Pair,
[Alias('CaseSensitive')][switch]$MatchCase
)
for ($i = 0; $i -lt $Pair.get_Count()) {
if ($Pair[$i] -is [Array]) {
$InputObject = $InputObject |Replace-String -MatchCase:$MatchCase $Pair[$i++]
}
else {
$Regex = $Pair[$i++]
$Substitute = if ($i -lt $Pair.get_Count() -and $Pair[$i] -isnot [Array]) { $Pair[$i++] }
if ($MatchCase) { $InputObject = $InputObject -cReplace $Regex, $Substitute }
else { $InputObject = $InputObject -iReplace $Regex, $Substitute }
}
}
$InputObject
}; Set-Alias Replace Replace-String
用法:
$lookupTable |Replace 'something1', 'something1aa', 'something2', 'something2bb', 'something3', 'something3cc'
或:
$lookupTable |Replace ('something1', 'something1aa'), ('something2', 'something2bb'), ('something3', 'something3cc')
示例:
'hello world' |Replace ('h','H'), ' ', ('w','W')
HelloWorld