代码之家  ›  专栏  ›  技术社区  ›  Eric

为什么从powershell调用批处理文件时插入符号消失?

  •  2
  • Eric  · 技术社区  · 6 年前

    这是我的 args.bat 文件:

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

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

    如果我从命令调用它,会发生以下情况:

    >.\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调用批处理文件时必须双引号引用参数?


    同样的问题不存在,因为Python调用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', '^']
    

    从命令中的python批处理:

    > python -c "import subprocess; subprocess.call(['args.bat', '^^^^^'])"
    ['-c', '^']
    
    1 回复  |  直到 6 年前
        1
  •  6
  •   mklement0    6 年前

    对于更大的问题 批处理文件是否可以可靠地中继任意参数 (剧透警告:不),见埃里克的 follow-up question .


    tl;博士 :

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

    使用 --% , the stop-parsing symbol ,使PowerShell按原样传递其余参数,但展开 cmd.exe -设置环境变量引用的样式,例如 %OS% .

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


    PowerShell ,作为一个shell本身,执行 拥有 先分析再分析-这是 窗户 - 重述引用 当为 外部程序 .

    这种做法随着时间的推移而改变,过去曾是许多问题的根源。 这些问题导致 --% 但是,如上所述,这也有其自身的挑战。

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

    不过,PowerShell重新引用了 有条件地 ,基于它是否认为 必要的 .

    在手头的案子里,因为 内容 PowerShell "^^^^^" 字符串包含 没有空白 ,PowerShell决定 不引用 传递到批处理文件时;即:

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

    有效地成为

    .\args.bat ^^^^^
    

    这对 外部程序,其中 ^ 没有 句法的 意思是,但如果是批处理文件(解释为 命令提示符 )这很重要,因为 ^ 用作转义字符。在那里没有引用的字符串。

    在这种情况下仍然强制使用双引号,作为 --% 上面的方法,您可以使用 嵌入的 双引号,正如您在问题中已经演示过的:

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

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

    那是因为 命令提示符 不涉及此场景,即使在从PowerShell调用时丢失了括起来的双引号,Python仍将 ^ 实例作为文本。

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

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

    那是因为你又打电话给 批量 文件 未引用 ^^^^^ 在这种情况下 命令提示符 ,因为 '....' 只有语法意义 蟒蛇 而不是通过-这重新引入了对 ^ .

    请注意 甚至调用批处理文件的“无壳”方法(例如 subprocess.call() 从Python)仍然总是调用 命令提示符 ,因为 命令提示符 是执行批处理文件所需的解释器。

    当经过一个 未引用 一串 ^^^^^ 对于一个批处理文件,似乎有两轮解释:首先,作为 参数分析 ,每个 ^^ 一对变成一对 ^ ,任何未配对的 ^ 被丢弃。 在批处理文件中 ,所以你看 ^^ ,如果使用时未加引号,它将变成一个 ^ -如果你引用双引号 %* %1 在批处理文件中,您将看到 ^^ 通过了。