Powershell Get-item -使用特殊字符和单引号替换问题

omqzjyyz  于 2023-05-29  发布在  Shell
关注(0)|答案(2)|浏览(114)

我试图取代一些文本在一堆的ps1脚本文件。通常这是没有问题的,但是当替换字符串包含像“$”这样的特殊字符沿着单引号时,我遇到了一些困难。我试过逃避特殊字符,但就是不能让它工作。我要替换的具体文本是。

'WORKVPN1*')

'WORKVPN1*') -and ($_.VPN -notlike 'WORKVPN2*')

我尝试了以下代码,但不起作用。

Get-ChildItem "C:\temp\*.ps1" | ForEach-Object -Process {(Get-Content $_) -Replace "'WORKVPN1*')" , "WORKVPN1*'`) -and `(`$_.VPN -notlike 'WORKVPN2*'`)" | Set-Content $_}
mftmpeh8

mftmpeh81#

对于 * 逐字 *(文字)替换,-replace,基于正则表达式的字符串替换操作符,需要 * 转义正则表达式操作数 * 和 * 替换操作数,尽管 * 使用不同的机制**。

  • 有关背景信息,请参见this answer
  • 除非您需要 * 预先字符串扩展 *(插值),否则在 * 结果 * 传递到底层.NET API之前,**避免使用可扩展(双引号)字符串("...")**和-replace(以及-matchswitch -Regex)。
  • 即使这样,最好使用逐字(单引号)字符串('...',如果需要,将它们用作 * 表达式 * 的一部分,以拼接动态部分

(e.g. 'a ' + $var + ' b'而不是"a $var b"

  • 使用'...'引用可以避免"..."字符串可能出现的潜在混淆,其中字符串的哪些部分由PowerShell预先扩展(插值),而不是由.NET正则表达式引擎最终看到的内容。
  • 值得注意的是,在替换操作数中,$_对正则表达式引擎有特殊的意义,但在"..."中使用它会扩展自动变量$_;比较'can' -replace '^', '$_'-它将输入字符串加倍,正如预期的那样(cancan)-与'can' -replace '^', "$_",它只产生can,因为自动$_变量在没有管道上下文的情况下扩展为 * 空字符串 *。

适用于您的案例:

Get-ChildItem C:\temp -Filter *.ps1 | 
  ForEach-Object {
    ($_ | Get-Content -Raw) -replace '''WORKVPN1\*''\)', 
                                     '$& -and ($$_.VPN -notlike ''WORKVPN2*'')"' | 
      Set-Content -LiteralPath $_.FullName
  }

注意事项:

  • ''需要转义'字符。嵌入在'...'字符串中
  • Regex元字符*)分别被\转义。
  • 或者,对于 * 编程式 * 转义,使用[regex]::Escape()
  • 替换操作数中的$&引用正则表达式捕获的内容(即,* 逐字 * 'WORKVPN1*')
  • $$用于转义替换操作数中的$字符,该字符将 * 逐字 * 使用-$字符是 * 唯一 * 需要在替换操作数中转义的字符-参见Substitutions in Regular Expressions

一个替代方法使用 * 逐字 *(文字)替换使用[string]类型的**.Replace() * 方法***,该方法 * 直接且排他地 * 执行逐字替换:

  • 然而,这需要在替换字符串中 * 重复 * 逐字部分。
  • 此外,此方法在Windows PowerShell中是 * 区分大小写 不变 *,并且 * 默认情况下 * 在PowerShell(Core)7+中。
  • 相比之下,PowerShell的-replace运算符默认情况下不区分大小写,并通过其-creplace变体提供大小写敏感性。

有关何时使用-replace.Replace() .

e7arh2l6

e7arh2l62#

-replace使用regex,所以转义regex字符。这个方法为你做到了。

[regex]::escape("'WORKVPN1*')")

'WORKVPN1\*'\)

.replace()不使用正则表达式,但这个重载区分大小写:

$string.replace("'WORKVPN1*')", "whatever")

我只是把星星和括号反斜线。在替换文本中不必对括号加反引号。$$是一个文本$替换的代码。

"'WORKVPN1*')" -Replace "'WORKVPN1\*'\)", 
  "WORKVPN1*') -and (`$`$_.VPN -notlike 'WORKVPN2*')"

WORKVPN1*') -and ($_.VPN -notlike 'WORKVPN2*')

顺便说一下,我不确定这些-replace代码埋在文档的哪里:

$number Substitutes the last submatch matched by group number.
${name} Substitutes the last submatch matched by a named capture of the form
(?<name>).
$$ Substitutes a single "$" literal.
$& Substitutes a copy of the entire match itself.
$` Substitutes all the text from the argument string before the matching portion.
$' Substitutes all the text of the argument string after the matching portion.
$+ Substitutes the last submatch captured.
$_ Substitutes the entire argument string.

在.replace()中,由于双引号的原因,您仍然需要对美元符号进行反引号。

"'WORKVPN1*')".Replace("'WORKVPN1*')",
  "WORKVPN1*') -and (`$_.VPN -notlike 'WORKVPN2*')")

WORKVPN1*') -and ($_.VPN -notlike 'WORKVPN2*')

相关问题