【问题标题】:Why do carets vanish when calling a batch file from powershell?为什么从 powershell 调用批处理文件时插入符号会消失?
【发布时间】:2018-08-09 01:42:46
【问题描述】:

这是我的args.bat 文件:

@echo off
python -c "import sys; print(sys.argv)" %*

我在这里调用 python 是因为我确切地知道如何解释输出,而不是猜测字符串中的引号

如果我从 cmd 调用它会发生以下情况:

>.\args.bat ^^^^^
More?
More?
['-c', '^']
>.\args.bat "^^^^^"
['-c', '^^^^^']

但这是 powershell 的作用:

PS> .\args.bat ^^^^^
['-c', '^']
PS> .\args.bat "^^^^^"
['-c', '^']
PS> .\args.bat '^^^^^'
['-c', '^']
PS> .\args.bat "'^^^^^'"
['-c', '^']
PS> .\args.bat '"^^^^^"'
['-c', '^^^^^']

为什么在从 powershell 调用批处理文件时必须双引号引用参数?


从powershell调用python不存在同样的问题:

PS> python -c "import sys; print(sys.argv)" "^^^^^"
['-c', '^^^^^']
PS> python -c "import sys; print(sys.argv)" '^^^^^'
['-c', '^^^^^']
PS> python -c "import sys; print(sys.argv)" ^^^^^
['-c', '^^^^^']

但是当从 powershell 从 python 调用批处理时仍然存在!

PS> python -c "import subprocess; subprocess.call(['args.bat', '^^^^^'])"
['-c', '^']

并从 cmd 中的 python 批处理:

> python -c "import subprocess; subprocess.call(['args.bat', '^^^^^'])"
['-c', '^']

【问题讨论】:

    标签: powershell batch-file escaping


    【解决方案1】:

    对于批处理文件是否可以可靠地传递任意参数(剧透警告:否)的更大问题,请参阅 Eric 的 follow-up question


    tl;dr

    PS> .\args.bat --% "^^^^^"
    ['-c', '^^^^^']
    

    使用--%, the stop-parsing symbol,使PowerShell按原样传递其余参数,除了扩展cmd.exe风格的环境变量引用,如%OS%

    相反,您将无法引用 PowerShell 变量或表达式。


    PowerShell 作为一个独立的 shell,首先执行它自己的 解析,然后 - Windows 上的一个不幸的必要性 - 在为外部程序编写命令行时重新应用引用。

    这种方式随着时间的推移发生了变化,过去一直是许多问题的根源。 这些问题导致了--% 的引入,如上所述,但它也有其自身的挑战。

    但是,重新引用通常是必要的,因为外部程序不一定能理解 PowerShell 的语法。
    最值得注意的是,'...' 引用不能被假定为所有外部程序都能理解,因此需要转换为 "..."

    然而,PowerShell 有条件地重新引用它,基于它是否认为它是必要

    在目前的情况下,因为 PowerShell "^^^^^" 字符串的 content 包含 no whitespace,PowerShell 决定 不在将其传递给批处理文件时引用它;即:

    .\args.bat "^^^^^"
    

    有效地变成

    .\args.bat ^^^^^
    

    这对于大多数外部程序来说很好,其中^没有语法含义,但对于批处理文件(由cmd.exe解释)它很重要,因为 ^ 用作转义字符。在未加引号的字符串中。

    要在这种情况下仍然强制使用双引号,作为上述 --% 方法的替代方法,您可以使用 embedded 双引号,正如您在问题中已经证明的那样:

    PS> .\args.bat '"^^^^^"' #  '...' quoting with embedded "..." quoting
    ['-c', '^^^^^']
    

    从powershell调用python不存在同样的问题:
    PS> python -c "import sys; print(sys.argv)" "^^^^^"

    这是因为cmd.exe 不涉及此场景,即使在从 PowerShell 调用时封闭的双引号丢失,Python 仍将 ^ 实例视为文字。

    但在从 powershell 从 python 调用批处理时仍然存在
    PS> python -c "import subprocess; subprocess.call(['args.bat', '^^^^^'])"

    从 cmd 中的 python 批处理: > python -c "import subprocess; subprocess.call(['args.bat', '^^^^^'])"

    那是因为您再次调用 batch 文件 - 在这种情况下,即使从 cmd.exe 使用 unquoted ^^^^^,因为封闭的 '....' 只有Python 的句法含义并且不会被传递 - 这重新引入了 ^ 的特殊解释。

    请注意,即使是调用批处理文件的“无壳”方法(例如 Python 中的 subprocess.call())仍然总是调用 cmd.exe,因为 cmd.exe 是执行所需的解释器批处理文件。

    当将 未引用 字符串 ^^^^^ 传递给批处理文件时,似乎有 2 轮解释:首先,作为 参数解析 的一部分,每个 @987654351 @pair 变为单个 ^,任何未配对的 ^ 都会被丢弃。 在批处理文件中,因此您会看到^^,当不加引号使用时,它会变成单个^ - 如果您在批处理文件中双引号%*%1会看到^^ 被通过了。

    【讨论】:

      猜你喜欢
      • 2013-02-12
      • 2015-09-18
      • 2014-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多