完美批量转发参数

2024-06-25

我有一个小的 python 脚本:

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

我怎样才能写一个.bat将所有参数转发给该脚本的包装文件?

为了从测试中消除我的 shell,我将调用它:

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

The 批处理文件的明显选择 https://stackoverflow.com/a/11637707/102441

@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"

但当在任意字符串上尝试时,很快就会崩溃:

>>> 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文件未经修改地传递其参数?


为了证明不是subprocess导致问题 - 尝试运行上面的

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

所有测试均按预期运行


类似问题:

  • 获取 Windows 批处理脚本 (.bat) 中传递的参数列表 https://stackoverflow.com/q/357315/102441- 不解决无损转发问题
  • 将传递的参数重定向到 Windows 批处理文件 https://stackoverflow.com/questions/980331/redirecting-passed-arguments-to-a-windows-batch-file- 解决了与我的问题相同的想法,但作为上述问题的重复项被错误地关闭,并且测试用例不太清晰
  • 将所有批处理文件参数转发到内部命令 https://stackoverflow.com/q/11637501/102441- 问题不考虑极端情况,接受的答案对他们不起作用

简而言之:没有稳健的方法通过批处理文件按原样传递参数,因为如何cmd.exe解释论点;注意cmd.exe is 总是涉及,因为它是执行批处理文件所需的解释器,即使您使用不要求 shell 参与的 API 调用批处理文件。

简而言之,问题是:

  • 在 Windows 上,调用外部程序需要使用命令行作为单串出于技术原因。因此,即使使用基于数组、无外壳的方式来调用外部程序也需要命令行的自动组成其中各个参数是embedded.

    • 例如,Python 的subprocess.check_output()单独接受目标可执行文件及其参数,作为数组的元素,如问题中所示。

    • 调用目标可执行文件directly,使用自动组成的命令行幕后,而不使用平台的 shell 作为中介(Python 的方式os.system()例如,调用确实) - 除非目标可执行文件发生这种情况itself要求 shell 作为执行解释器,就像这样cmd.exe对于批处理文件。

  • 编写命令行需要选择性双引号 and 逃脱embedded " chars.嵌入各个参数时;通常涉及:

    • 使用封闭的双引号 ("..."),但仅限于包含空格(空格)的参数。
    • 将嵌入的双引号转义为\"
    • 尤其,没有其他字符触发双引号或单独转义,即使这些字符对于给定的可能具有特殊含义shell.
  • 虽然这种方法适用于大多数外部程序,但它不能可靠地工作批处理文件:

    • 很遗憾,cmd.exe不将参数视为literals,但将它们解释为好像您已在某个文件中提交了批处理文件调用交互式控制台(命令提示符)。

    • 结合命令行的组成方式(如上所述),这会在很多方面导致参数可能被误解并完全破坏调用.

      • 首要问题是最终的争论unquoted在命令行中cmd.exe看到五月break调用,即如果它们包含诸如& , |, > or <。 即使调用没有中断,字符如^可能得到被误解.

        • 有关有问题的论点的具体示例,请参阅下文。
      • 尝试解决该问题主叫方 with 嵌入引用- 例如,使用'"^^^^^"作为 Python 中的参数 -does not work,因为大多数语言,包括 Python,都使用\"逃离"幕后人物,cmd.exe does not识别(它只识别"").

        • 假设你可以煞费苦心^-escape 个人无空格参数中的字符,但这不仅非常麻烦,而且仍然无法解决所有问题 - 见下文。
      • 杰布的回答 https://stackoverflow.com/a/51761162/45375值得称赞的地址some这些问题中在批处理文件内,但它相当复杂,也无法解决所有问题 - 请参阅下一点。

    • 无法解决以下问题基本的限制:

      • cmd.exe从根本上无法处理带有嵌入换行符(换行符)的参数:

        • 简单地解析参数列表stops在遇到的第一个换行符处。

        • CR (0xD) 字符。被隔离地悄悄地移除。

      • The 的解释%作为环境变量参考的一部分(例如,%OS%) 无法被抑制:

        • %%没有帮助,因为,奇怪且不幸的是,交互的cmd.exe 会话 apply(!),其中抑制扩展的唯一方法是使用“变量名破坏者技巧”,例如 %^OS%,它仅适用于unquoted参数 - 在双引号争论,你从根本上无法阻止扩张。

        • 如果环境你很幸运。多变的碰巧不存在;然后将令牌单独保留(例如,%NoSuchVar% or %No Such Var%(注意cmd.exe does支持带空格的变量名)。

无空格参数的示例,这些参数要么中断批处理文件调用,要么导致不必要的值更改:

  • ^^^^^

    • ^在不带引号的字符串中是cmd.exe的转义字符,转义next字符,即将其视为literal; ^^因此代表一个字面的、单一的^,所以上面的结果是^^,与最后一个^被丢弃
  • a|b

    • |分隔管道中的命令,因此cmd.exe将尝试在之前通过管道传输命令行部分|到一个名为b并且调用很可能break或者,也许更糟糕的是,无法按预期工作and执行一些不应该执行的事情。

      • 为了使其工作,您需要将参数定义为'a^^^|b'(原文如此)在Python方面。
    • 注意a & b would not会受到影响,因为嵌入的空格会触发Python端的双引号,并且使用& inside "..."是安全的。

    • 造成类似问题的其他角色是& < >

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

完美批量转发参数 的相关文章