我終于縮小了問題的范圍,但需要幫助理解原因。
從批處理檔案呼叫 Powershell,以下作業可以替換檔案中的字串:
Powershell -Command "$foobar=[IO.File]::ReadAllText("$Env:File") ;
$foobarred= $foobar -replace '(?<foo>.*Backup.).*.(?<bar>..Backup.)', '${foo}Enabled${bar}' ;
[IO.File]::WriteAllText("$Env:File", $foobarred); "
現在,如果我嘗試此操作,命令將失敗:
Powershell -Command "$foobar=[IO.File]::ReadAllText("$Env:File") ;
$foobarred= $foobar -replace '(?<foo>.*$Env:StrStart.).*.(?<bar>..$Env:StrEnd.)', '${foo}$Env:StrVal${bar}' ;
[IO.File]::WriteAllText("$Env:File", $foobarred); "
如果我使用從 Batch 傳入的變數,它每次都會失敗。如果我在命令中使用 PlainText 代替替換值,它作業得很好。為什么會發生這種情況?
uj5u.com熱心網友回復:
我的觀察是
[regex]::Escape()動態構建正則運算式時需要任意值。- PowerShell 不會在單引號字串中進行任何字串插值,因此諸如此類的事情
'${foo}$Env:StrVal${bar}'不會按您想要的方式作業。
我會使用以下命令:
(Get-Content "filename" -Raw) -replace (
'(.*' [regex]::Escape("start string") '.).*.(..' [regex]::Escape("end string") '.)'
),(
'$1' "replacement string" '$2'
) | Set-Content "filename"
從批處理檔案中呼叫 ad-hoc 如下(壓縮到一行):
@echo off
setlocal
set "FILENAME=filename"
set "START=start string"
set "END=end string"
set "REPLACEMENT=replacement string"
set "PSCMD=(gc $Env:FILENAME -Raw) -replace ('(.*' [regex]::Escape($Env:START) '.).*.(..' [regex]::Escape($Env:END) '.)'),('$1' $Env:REPLACEMENT '$2') | sc $Env:FILENAME"
powershell -NoLogo -Command "&{%PSCMD%}"
但這不成比例地難以維持。
我建議撰寫一個 .ps1 檔案并傳遞命名引數,而不是處理環境變數。
# MyReplace.ps1
param(
[string]$Filename,
[string]$Start,
[string]$End,
[string]$Replacement
)
$ErrorActionPreference = "Stop"
$content = Get-Content $Filename -Raw
$content = $content -replace ('(.*' [regex]::Escape($Start) '.).*.(..' [regex]::Escape($End) '.)'),('$1' $Replacement '$2')
$content | Set-Content $Filename
并批量
powershell -NoLogo -File MyReplace.ps1 -Filename "filename" -Start "start string" -End "end string" -Replacement "replacement string"
這對我來說似乎更易于管理。
uj5u.com熱心網友回復:
在@Gerhard 的建議下,將我發現的內容作為答案添加到了爭論中,但最終確實讓@Tomalak 獲得了整體更好答案的功勞。
為了在匹配模式和替換模式中都接受變數,您必須連接字串(類似于在 Visual Basic 中的操作方式)。
參考如下:
為了便于閱讀,我已將命令分成多行 - 如果您使用它,請將其放在一行上。
重要 - 使用它時,如果在批處理檔案中使用它,請確保洗掉換行符。 另外 - 小心 - 我在某些情況下甚至使用 Set-Content 也可以更改檔案的編碼。我更喜歡下面提供的輔助解決方案。
Powershell -Command "$pattern= '(?<RangeStart>.*' [regex]::Escape($Env:StrStart) '.).*.(?<RangeEnd>..' [regex]::Escape($Env:StrEnd) '.)' ;
$repl= '${RangeStart}' $Env:StrVal '${RangeEnd}' ;
$fil2parse=(Get-Content $Env:FileTOParse) -replace $pattern, $repl | Set-Content $Env:FileTOParse; "
這個解決方案也有效,但我在更改編碼時遇到的問題要少得多。
Powershell -Command "$pattern= '(?<RangeStart>.*' [regex]::Escape($Env:StrStart) '.).*.(?<RangeEnd>..' [regex]::Escape($Env:StrEnd) '.)' ;
$repl= '${RangeStart}' $Env:StrVal '${RangeEnd}' ;
$fil2parse=[IO.File]::ReadAllText("$Env:FileTOParse") ;
$filParsed= $fil2parse -replace $pattern, $repl ;
[IO.File]::WriteAllText("$Env:FileTOParse", $filParsed); "
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/345213.html
