vonPryz's helpful answer 很好地覆盖了 PowerShell-internal 角度;让我尝试一个系统的总结,包括 PowerShell CLI 角度,以及将带有嵌入式 " 的参数传递给外部程序:
在一个PowerShell会话中,唯一转义字符是`(所谓的反引号),在以下情况下:
-
在expandable string("...",双引号)内,但不在在verbatim string('...',单引号)内;对于支持的转义序列,请参阅概念性about_Special_Characters 帮助主题:
# " must be escaped; escape sequence `n expands to a newline.
"3`" of`nrain"
-
在未引用的命令参数中:
# > must be escaped to write verbatim 'a>b',
# since outside a quoted string an unescaped > is a redirection.
Write-Output a`>b
-
对于行继续:
# Spread the Get-Date call across two lines.
# Important: ` must be the *very last char* on the line.
Get-Date `
-Year 2525
-
注意:各种子系统,无论是否特定于PowerShell,都可能有自己的转义规则,例如regular expressions 中的\ 和wildcard expressions 中的`。由于这些子系统的参数是通过 PowerShell 字符串 传递的,因此最好使用 逐字 字符串文字,以避免 PowerShell 自己的字符串插值与目标子系统最终结果之间的混淆看见;例如'A $50 fine.' -match '\$50'(需要\ 来处理正则表达式元字符$ 字面意思)。
当从外部调用 PowerShell 时,通过其 CLI,不同的规则适用,可能另外 em>:
为了遵守 Windows 上广泛使用的 CLI 约定(命令行界面,通过命令行接受参数的程序):
-
在对 powershell.exe 的调用中,Windows PowerShell CLI、" 字符必须使用转义反斜杠 - 即\" - 以便在解析原始命令行期间保留。
-
pwsh.exe,跨平台按需安装的 CLI PowerShell (Core) 7+ edition,现在值得称道的是可选 接受""[1] 代替\",这使得来自cmd.exe 的调用更加健壮。要在 Windows PowerShell 中获得相同的稳健性 - 仅来自 cmd.exe - 使用 "^""(原文如此)。
请注意 - 与 \" 不同 - 这些转义序列仅在(未转义的)"..." 字符串中工作(例如,pwsh.exe -c " ""you & I"" " 或 powershell.exe -c " "^""you & I"^"" "
相比之下,未转义"在命令行上有语法函数,并告诉PowerShell参数之间的边界在哪里;这些" 实例在命令行解析过程中删除。
这确保外部调用者只想使用-File 参数调用带有参数的PowerShell 脚本文件 (.ps1),可以使用常规的语法并且不需要对 PowerShell 的 CLI 进行特殊情况调用。
但是,如果您使用 -Command 参数将包含 PowerShell 代码的字符串传递给 CLI,那么 PowerShell 最终解释的内容显然必须是语法上有效的 PowerShell 代码.
警告:如果您既未指定 -Command 也未指定 -File:
-
powershell.exe 默认为 -Command
-
pwsh.exe 现在默认为 -File
有关-File 和-Command 调用之间的区别以及何时使用,请参阅this answer。
如果使用-Command,则有两个,顺序解析阶段:
因此,您可能需要结合\ 和`-escaping;例如(来自cmd.exe的电话):
C:>powershell.exe -Command " \"3`\" of snow as of $(Get-Date)\" "
3" of snow as of 11/04/2021 14:13:41
注意使用`\" 以使PowerShell 看到`",即在"..." 字符串中正确转义",在命令行解析之后。
或者,根据您传递给-Command 的命令的具体情况,使用嵌入的'...' 引用可能是一个选项,这可以简化问题,因为' 字符。不需要转义:
C:>powershell.exe -Command " '3\" of snow as of today.' "
3" of snow as of today.
鉴于 PowerShell 中的 '...' 字符串是 verbatim strings,只有在不需要字符串插值(例如前面示例中的 $(Get-Date) 子表达式)时才可以使用 '...'。
从 PowerShell 调用外部程序时转义":
作为 shell,PowerShell 的工作是将基于 its 语法规则传递的参数传递给目标可执行文件,以便从PowerShell 的解析以使目标可执行文件看到它们的方式传递。换句话说:PowerShell 应该在幕后自动执行任何需要的转义。 (与cmd.exe 不同,PowerShell 不能按原样传递自己的参数语法,因为不能期望外部 CLI 能够理解 '...' 字符串(单引号)或 `-转义)。
举一个简单的例子:传递'3" of snow' 应该在幕后传递"3\" of snow",基于最广泛使用的转义约定。
遗憾的是,至少达到 PowerShell 7.2(撰写本文时为当前版本),不是这种情况,并且在参数中嵌入了" 字符对于外部程序必须另外手动为\-escaped才能正确通过。
# Broken behavior up to at least PS v7.2
PS> cmd /c echo '{ "foo": "bar" }'
"{ "foo": "bar" }" # !! Embedded " aren't escaped.
PS> choice.exe /d Y /t 0 /m '{ "foo": "bar" }'
{ foo: bar } [Y,N]?Y # !! When parsed by an executable,
# !! embedded " are effectively LOST.
# Manual escaping required.
PS> choice.exe /d Y /t 0 /m '{ \"foo\": \"bar\" }'
{ "foo": "bar" } [Y,N]?Y # OK
这个错误从 v1 开始就存在,并且从未被修复以避免破坏现有的解决方法。
这可能最早会在 v7.3 中更改 - 以及修复是否需要选择加入我不清楚,而且看起来不符合标准的 Windows CLI 的高调异常也不会被容纳。
有关更多信息,请参阅this answer,其中包括相关 GitHub 问题的链接。
[1] 在 PowerShell 中,仅在 "..." 字符串中,您也可以使用 "" 转义嵌入的 ",作为 `" 的替代方案