【问题标题】:Escaping dollar signs in PowerShell path is not working在 PowerShell 路径中转义美元符号不起作用
【发布时间】:2020-10-15 16:43:23
【问题描述】:

为什么这不起作用?


$drvrInstFilePath = "$sharePath\$imageName\ISO`$OEM$`$1\RPKTools\RPKDriverInst.bat"
echo $drvrInstFilePath
$drvrInstContent = Get-Content -LiteralPath "$sharePath\$imageName\ISO`$OEM$`$1\RPKTools\RPKDriverInst.bat"  | Out-String

echo 显示了正确的路径,但 Get-Content 命令将 $oem 和 $1 扩展为空白字符串,即使它们被转义。为什么?

【问题讨论】:

  • 当你运行上面的脚本时,你会得到什么输出?我无法复制你的问题。还有你用的是什么版本的powershell?
  • PS 2.0。而且我刚才也复制不了,一定是疯了。

标签: powershell


【解决方案1】:

不要乱用转义美元符号,而是使用单引号 ' 而不是双引号 "。它可以防止 PowerShell 将 $ 扩展为变量。像这样,

$p = "C:\temp\Share\ISO$OEM$"
# Output
C:\temp\Share\ISO$


$p = 'C:\temp\Share\ISO$OEM$'
# Output
C:\temp\Share\ISO$OEM$

如果您需要使用变量创建路径,请考虑使用Join-Path。像这样,

$s = "Share"
join-path "C:\temp\$s" '\ISO$OEM$' 
# Output
C:\temp\Share\ISO$OEM$

【讨论】:

  • 谢谢,join-path 把我带到了我要去的地方。
  • 在最后一个例子中,如果下一行使用明显为空的$share,那么定义$s = share 有什么意义? (如输出所示,temp\Share,大写 S,来自 join-path 的第二个参数)
  • @quetzalcoatl 我认为第一行的意思是$share = ""
【解决方案2】:

您实际上可以像这样使用刻度线来转义$

`$

例子:

$number = 5
Write-Host "`$${number}"
# Output: $5

【讨论】:

  • dafuq 为什么这么低:')
  • 我喜欢这个解决方案。改用单引号可能会解决一个问题,但会引入一堆其他问题——尤其是在我的实例中,我在 pwsh 变量中搞乱了 T-SQL。反引号很简单,而且很重要。不错的一个:-)
  • 当然,这应该是公认的解决方案
【解决方案3】:

您使用了双引号和一个反引号。这是不正确的组合。事实上,我不确定在 any 情况下单独一个反引号就足够了。在 PowerShell 中转义美元符号 ($) 的成功选项是使用带有反斜杠-反引号组合的双引号 ("\`$find"),或者使用带有简单反斜杠的单引号('\$find')。 [但是,请注意最后关于函数调用参数的异常。] 请参阅下面的示例。

此外,对于那些不熟悉区别的人,重要的是不要将 反引号 字符 (`)单引号 混淆这些转义中的字符 (')

[SUCCESS] 双引号作为容器,反斜杠-反引号作为转义:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace "\`$old", "(New)"}
What is (New)?
PS C:\Temp>

[FAIL] 双引号作为容器,反斜杠撇号作为转义:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace "\'$old", "(New)"}
What is $old?
PS C:\Temp>

[SUCCESS] 单引号作为容器,用简单的反斜杠作为转义:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace '\$old', "(New)"}
What is (New)?
PS C:\Temp>

[FAIL] 单引号作为容器,反斜杠-反引号作为转义:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_ -replace '\`$old', "(New)"}
What is $old?
PS C:\Temp>

总的来说,最简单的选择可能是使用单引号作为容器,使用单反斜杠作为转义:'\$old'

更新:好像上面的内容还不够混乱,当您使用函数调用而不是命令时,需要单引号没有转义。尝试在函数调用参数上使用转义将起作用:

[FAIL]在函数参数中使用转义:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_.ToString().Replace('\$old', "(New)");}
What is $old?
PS C:\Temp>

[SUCCESS]在函数参数中使用没有转义的纯单引号:

PS C:\Temp> 'What is $old?' | ForEach-Object {$_.ToString().Replace('$old', "(New)");}
What is (New)?
PS C:\Temp>

【讨论】:

  • 另外,如果在函数调用中你使用了"-quotes,$old 执行字符串插值,你必须用 .. 单反引号将其转义。没有反斜杠。这实际上是有道理的,因为反斜杠是非 funcall 语法中的额外转义。无论如何,当我尝试使用字符串插值和捕获组替换来调用 Regex.Replace 时,我发现了它:$regex.Replace($rawtext, "$keyword: `$1")。如果没有反引号,$1 将在传递给 Replace 之前进行字符串插值,并且总是会在那里产生空文本,因为没有这样的变量。
  • 我不认为“带有反斜杠-反引号组合的双引号”(“`$find”)在 PowerShell 5.0 中不再起作用......根据 Windows PowerShell 语言规范版本 3.0 第 30 页,一个反引号就足够了。
  • 因为 -Replace 运算符使用正则表达式,不幸的是,这些示例将使用反引号的正常 PowerShell 转义与使用反斜杠的正则表达式转义混淆了。纯 PowerShell 字符串不使用反斜杠进行转义。
【解决方案4】:

在我的情况下,我需要转义字符串中使用的一些 $,而不是其他变量。

例如,我的 SSRS 实例名称有一个$ 符号:

[报表服务器$SSRS]

为了转义 $ 符号,我使用单引号。否则,我使用-join 语句将变量与包含实际 $ 符号的字符串连接起来。

 $sql = -join('ALTER DATABASE [ReportServer$', $instanceName,'TempDB]
  SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
  GO

  USE [master]
  RESTORE DATABASE [ReportServer$', $instanceName,'TempDB] FROM  DISK = N''C:\temp\ReportServerTempDB.BAK'' WITH  FILE = 1,
    MOVE N''ReportServerTempDB'' TO N''', $sqlDataDrive + "\data_" + $instanceName, '\ReportServer$', $instanceName,'TempDB.mdf'', 
    MOVE N''ReportServerTempDB_log'' TO N''', $sqlLogDrive + "\log_" + $instanceName, '\ReportServer$', $instanceName,'_TempDBlog.LDF'',  NOUNLOAD,  REPLACE, RECOVERY,  STATS = 5
  GO

  ALTER DATABASE [ReportServer$', $instanceName,'TempDB]
  SET MULTI_USER;
  GO
  ')

【讨论】:

    猜你喜欢
    • 2022-12-02
    • 2015-06-17
    • 2021-07-01
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-25
    相关资源
    最近更新 更多