【问题标题】:What is the difference between the escape backtick "`" and backslash "\" in PowerShell?PowerShell中的转义反引号“`”和反斜杠“\”有什么区别?
【发布时间】:2021-11-04 09:49:47
【问题描述】:

我知道两者都在 PowerShell 中使用,但用于不同的上下文。

互联网上关于这个话题的信息很少,唯一谈论它的网站(没有让我理解这个概念)是:
https://www.rlmueller.net/PowerShellEscape.htm

我是 PowerShell 的初学者,我最近正在接近它。
\ 转义的用例出现在我的另一个主题的答案中:
PowerShell removes multiple consecutive whitespaces when I pass arguments to a nested Start-Process command

有没有人可以详细解释一下PowerShell中转义反引号`和反斜杠\之间的区别,并附上示例和用例?

欢迎至少一个来源,但这不是强制性的。

【问题讨论】:

    标签: powershell escaping


    【解决方案1】:

    反引号 ` 在 Powershell 中用作 escape character。也就是说,转义引号、制表符和诸如此类的东西。与许多其他环境不同,Powershell 的换行符是`n,而不是\n。这具有简化路径的好处,因为它们在 Windows 中使用反斜杠。

    作为一个实际示例,在许多编程语言中,需要转义路径中的反斜杠。如果您的应用程序位于

    c:\program files\newApplication\myApp.exe
    

    它的路径必须写成

    c:\\program files\\newApplication\\myApp.exe
    

    双反斜杠表示实际上有一个反斜杠,而不是诸如制表符或换行符之类的元字符。请注意,路径包含\newApplication。现在,\n 通常表示换行符,但显然不是这样。该文件不驻留在

    c:\program files\
    ewApplication\myApp.exe
    

    毕竟,不是吗?

    Powershell 中不需要转义,因为反斜杠本身没有特殊含义。当 Powershell 看到c:\program files\newApplication\myApp.exe 时,它并没有给前面提到的\n 部分赋予任何特殊含义,它只是一个字符串文字。

    反斜杠\ 用作正则表达式中的转义字符并表示元字符。也就是说,要匹配正则表达式中的文字 *,必须对其进行转义,以免它表示 Kleene 星号(零个或多个匹配项)。

    【讨论】:

    • 但是在我的另一个主题的答案中是必要的,并且在您列出的那些中不是这种情况:stackoverflow.com/questions/69827746/…
    • 这是因为 \" 转义用于通过调用新进程将值传递给 wscript VBScript 解释器。
    • 但是wscript在传递参数时不需要\反斜杠,既不直接从PowerShell调用也不从cmd调用。你能更好地解释一下自己吗?
    • @MarioPalumbo 这是因为包括 PowerShell.exe 在内的大多数外部程序都依赖 CommandLineToArgvW Windows API 函数来处理命令行参数。这需要\" 语法。所以当从 PowerShell 调用可执行文件时,必须考虑 PowerShell 层的转义(以便 PowerShell 在调用程序之前正确解析)和被调用程序所需的转义。
    【解决方案2】:

    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,则有两个,顺序解析阶段:

    • 命令行解析阶段,其中句法(未转义)"删除,转义\"(或"")变成文字@ 987654376@.

    • 此阶段的结果然后解析为PowerShell代码,就像它来自PowerShell会话内部一样。

    因此,您可能需要结合\`-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 中,仅在 "..." 字符串中,您也可以使用 "" 转义嵌入的 ",作为 `" 的替代方案

    【讨论】:

    • 哇,解释得真好!这是我正在寻找的解释,非常感谢。这将对用户的帮助有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    • 2015-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 1970-01-01
    相关资源
    最近更新 更多