批量完美转发参数 [英] Perfectly forwarding arguments in batch

查看:113
本文介绍了批量完美转发参数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小的python脚本:

I have a small python script:

# args.py
import sys; print(sys.argv)

如何编写 .bat 封装文件是否将所有参数转发到该脚本?

How can I write a .bat wrapper file that forwards all of the arguments to this script?

要从测试中删除我的shell,我将其调用为: / p>

To eliminate my shell from the tests, I'm going to invoke it as:

import subprocess
import sys
def test_bat(*args):
    return subprocess.check_output(['args.bat'] + list(args), encoding='ascii')






批处理文件的明显选择

@echo off
python args.py %*

适用于简单情况:

>>> test_bat('a', 'b', 'c')
"['args.py', 'a', 'b', 'c']\n"
>>> test_bat('a', 'b c')
"['args.py', 'a', 'b c']\n"

但是在尝试使用任意字符串时迅速崩溃:

But rapidly falls apart when tried on arbitrary strings:

>>> test_bat('a b', 'c\n d')
"['args.py', 'a b', 'c']\n"  # missing d
>>> test_bat('a', 'b^^^^^c')
"['args.py', 'a', 'b^c']\n"  # missing ^^^^

甚至有可能使 bat 文件通过

证明其不是子流程问题-尝试使用

To prove it's not subprocess causing the issue - try running the above with

def test_py(*args):
    return subprocess.check_output([sys.executable, 'args.py'] + list(args), encoding='ascii')

所有测试的行为均符合预期

All of the tests behave as expected

类似问题:

  • Get list of passed arguments in Windows batch script (.bat) - does not address lossless forwarding
  • Redirecting passed arguments to a windows batch file - addresses the same ideas as my question, but incorrectly closed as a duplicate of the above, and with less clear test-cases
  • Forwarding all batch file parameters to inner command - question does not consider corner-cases, accepted answer does not work for them

推荐答案

简而言之:没有可靠的方法通过批处理文件按原样传递参数,由于 cmd.exe 如何解释参数;请注意, cmd.exe 总是 涉及,因为它是执行批处理文件所需的解释器,即使您使用不需要外壳程序参与的API。

In short: There is no robust way to pass arguments through as-is via a batch file, because of how cmd.exe interprets arguments; note that cmd.exe is invariably involved, given that it is the interpreter needed to execute batch files, even if you invoke the batch file using an API that requests no shell involvement.

问题简而言之:


  • 在Windows上,出于技术原因,调用外部程序需要使用命令行作为单个字符串 。因此,即使使用基于数组的,无外壳程序的方式来调用外部程序,也需要自动编写命令行,在该命令行中,嵌入了各个参数

  • On Windows, invoking an external program requires use of a command line as a single string for technical reasons. Therefore, even using an array-based, shell-free way of invoking an external program requires automated composition of a command line in which the individual arguments are embedded.


  • 例如,Python的 subprocess.check_output()接受目标可执行文件及其参数

  • E.g., Python's subprocess.check_output() accepts the target executable and its arguments individually, as the elements of an array, as demonstrated in the question.

使用命令直接调用目标可执行文件 幕后自动组成的一行,而无需使用平台的外壳作为中介(Python的 os.system()调用的方式,例如)-除非发生这种情况,否则目标可执行文件本身要求将外壳程序作为执行解释器,对于 cmd.exe 来说就是这种情况文件。

The target executable is invoked directly, using a command line that was automatically composed behind the scenes, without using the platform's shell as an intermediary (the way that Python's os.system() call does, for instance) - unless it so happens the target executable itself requires that shell as the executing interpreter, as is the case with cmd.exe for batch files.

编写命令行需要选择性双引号转义<嵌入单个参数时,em> embedded 字符。通常涉及以下内容:

Composing the command line requires selective double-quoting and escaping of embedded " chars. when embedding the individual arguments; typically that involves:


  • 使用双引号( ... ),但仅在包含空格(空格)的参数周围。

  • 将嵌入式双引号转义为 \

  • 值得注意的是,没有其他字符触发双引号或个别转义,即使这些字符对于给定的 shell 可能具有特殊含义。

  • Using enclosing double-quoting ("..."), but only around arguments that contain whitespace (spaces).
  • Escaping embedded double quotes as \"
  • Notably, no other characters trigger double-quoting or individual escaping, even though those characters may have special meaning to a given shell.

尽管这种方法对大多数外部程序都有效,但是批处理文件却不可靠

While this approach works well with most external programs, it does NOT work reliably with batch files:


  • 不幸的是, cmd.exe 不会将参数视为 literals ,而是将其解释为好像您已在交互式控制台(命令提示符)中提交了批处理文件调用。

  • Unfortunately, cmd.exe doesn't treat the arguments as literals, but interprets them as if you had submitted the batch-file call in an interactive console (Command Prompt).

结合了命令行的组成方式(如上所述),这会导致以多种方式对参数进行误解和bre

Combined with how the command line is composed (as described above), this results in many ways that the arguments can be misinterpreted and break the invocation altogether.


  • 主要问题是结尾的参数 cmd.exe 看到的命令行中可能会中断调用,即如果它们包含诸如& | > <
    即使调用不会中断,诸如 ^ 之类的字符也可能会被误解

  • The primary problem is that arguments that end up unquoted in the command line that cmd.exe sees may break the invocation, namely if they contain characters such as & , |, > or <. Even if the invocation doesn't break, characters such as ^ may get misinterpreted.


  • 有关问题性论证的具体示例,请参见下文。

尝试使用嵌入引用 解决调用方上的问题-例如,使用' ^^^^^ 作为Python中的参数-不起作用 ,因为大多数语言(包括Python)都使用 \ 躲在幕后的 个字符中,其中 cmd.exe 不能识别(它只能识别 )。

Trying to work around the problem on the calling side with embedded quoting - e.g., using '"^^^^^" as an argument in Python - does not work, because most languages, including Python, use \" to escape " characters behind the scenes, which cmd.exe does not recognize (it only recognizes "").


    假设,您可以在无空格的参数中使用 ^ -escape individual 字符,但这样做不仅麻烦,而且仍然会很麻烦无法解决所有问题-参见下文。
  • Hypothetically, you could painstakingly ^-escape individual characters in whitespace-free arguments, but not only is that quite cumbersome, it still wouldn't address all issues - see below.

Jeb的答案值得称赞的是在批处理文件中一些问题,但是它相当复杂,也无法解决所有问题-请参阅下一点。 p>

Jeb's answer commendably addresses some of these issues inside the batch file, but it is quite complex and it too cannot address all issues - see next point.

没有办法解决以下基本限制

There is no way to work around the following fundamental restrictions:


  • cmd.exe 从根本上不能使用嵌入的换行符(换行符)来处理参数

  • cmd.exe fundamentally cannot handle arguments with embedded newlines (line breaks):


  • 仅通过 stops来解析参数列表

  • Parsing the argument list simply stops at the first newline encountered.

CR( 0xD )字符。

%<的解释作为环境变量引用的一部分(例如%OS%)不能被抑制

The interpretation of % as part of an environment-variable reference (e.g, %OS%) cannot be suppressed:


  • %% 没有帮助,因为奇怪的是,不幸的是,的解析规则交互式 cmd.exe会话apply(!),其中抑制扩展的唯一方法是采用变量名破坏器技巧,例如%^ OS%,该技巧只能在未引用参数-在双引号参数中,从根本上讲您无法阻止扩展。

  • %% does NOT help, because, curiously and unfortunately, the parsing rules of an interactive cmd.exe session apply(!), where the only way to suppress expansion is to employ the "variable-name disrupter trick", e.g., %^OS%, which only works in unquoted arguments - in double-quoted arguments, you fundamentally cannot prevent expansion.

如果您的环境很幸运,您会很幸运。变量可能不存在;然后将令牌保留为空(例如,%NoSuchVar%%No Such Var%(请注意, cmd.exe 不支持带空格的变量名。)

You're lucky if the env. variable happens not to exist; the token is then left alone (e.g., %NoSuchVar% or %No Such Var% (note that cmd.exe does support variable names with spaces).

无空格参数的示例会中断批处理文件调用或导致值的不必要更改


  • ^^^^^


  • ^ 未引用的字符串是 cmd.exe 的转义字符,可转义 next 字符,即将其视为 literal ; ^^ 因此代表一个文字,单个 ^ ,因此上面的结果为 ^^ ,最后一个 ^ 被丢弃

  • ^ in unquoted strings is cmd.exe's escape character that escapes the next character, i.e., treats it as a literal; ^^ therefore represents a literal, single ^, so the above yields ^^, with the last ^ getting discarded

a | b


  • | 分隔管道中的命令,因此 cmd.exe 将尝试通过管道将命令行的一部分将 | 移至名为 b 的命令,则调用很可能会 break 或更糟糕的是,它们无法按预期的方式运行,并且执行不应执行的操作。

  • | separates commands in a pipeline, so cmd.exe will attempt to pipe the part of the command line before | to a command named b and the invocation will most likely break or, perhaps worse, will not work as intended and execute something it shouldn't.


  • 要实现此目的,您d需要在Python端将参数定义为'a ^^^ | b'(原文如此)。

  • To make this work, you'd need to define the argument as 'a^^^|b' (sic) on the Python side.

请注意, a& b 不会受到影响,因为嵌入式空格会在Python端触发双引号,并使用& ... 中的c>是安全的。

Note that a & b would not be affected, because the embedded whitespace would trigger double-quoting on the Python side, and use of & inside "..." is safe.

其他出现类似问题的字符是& < >

Other characters that pose similar problems are & < >

这篇关于批量完美转发参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆