Python 子流程参数列表太长

Python 子流程参数列表太长,python,linux,windows,python-3.x,Python,Linux,Windows,Python 3.x,我有一个使用subprocess.check_output调用的第三方可执行文件。不幸的是,我的参数列表太长,重复调用它比使用多个参数调用一次要慢得多 由于多次执行命令调用,速度较慢: def call_third_party_slow(third_party_path, files): for file in files: output = subprocess.check_output([third_party_path, "-z", file]) i

我有一个使用subprocess.check_output调用的第三方可执行文件。不幸的是,我的参数列表太长,重复调用它比使用多个参数调用一次要慢得多

由于多次执行命令调用,速度较慢:

def call_third_party_slow(third_party_path, files):
    for file in files:
        output = subprocess.check_output([third_party_path, "-z", file])
        if "sought" in decode(output):
            return False
    return True
快速,但在有多个文件时失败:

def call_third_party_fast(third_party_path, files):
    command = [third_party_path, "-z"]
    command.extend(files) 
    output = subprocess.check_output(command)
    if "sought" in decode(output):
        return False
    return True

是否有任何简单的方法可以绕过命令长度限制或轻松地对文件进行分组以避免超过操作系统相关的长度?

您可以按如下方式批处理文件列表:

def batch_args(args, arg_max):
    current_arg_length = 0
    current_list = []
    for arg in args:
        if current_arg_length + len(arg) + 1 > arg_max:
            yield current_list
            current_list = [arg]
            current_arg_length = len(arg)
        else:
            current_list.append(arg)
            current_arg_length += len(arg) + 1
    if current_list:
        yield current_list
os_limit = 10
for args in batch_args(files, os_limit):
    command = [third_party_path, "-z"]
    command.extend(args) 
    output = subprocess.check_output(command)
    if "sought" in decode(output):
        return False
return True
因此,方法体将如下所示:

def batch_args(args, arg_max):
    current_arg_length = 0
    current_list = []
    for arg in args:
        if current_arg_length + len(arg) + 1 > arg_max:
            yield current_list
            current_list = [arg]
            current_arg_length = len(arg)
        else:
            current_list.append(arg)
            current_arg_length += len(arg) + 1
    if current_list:
        yield current_list
os_limit = 10
for args in batch_args(files, os_limit):
    command = [third_party_path, "-z"]
    command.extend(args) 
    output = subprocess.check_output(command)
    if "sought" in decode(output):
        return False
return True
有两件事我不确定:

  • exe本身的路径是否计入限制?如果是->将其添加到每个批次的限制中。(或将arg_max减少exe字符串的长度)
  • arg之间的空格是否算数?如果不是,则删除两个+1事件
  • 尽可能调整arg_max。也许每个操作系统都有办法找到答案。是关于某些操作系统的最大参数大小的一些信息。该网站还声明windows有32k的限制

    也许有更好的方法使用子流程库来完成,但我不确定


    此外,我没有做任何异常处理(列表中的参数长度超过最大大小等)

    如果您不想重新发明最佳解决方案,请使用一个已经实现了这一点的工具:
    xargs

    def call_third_party_slow(third_party_path, files):
        result = subprocess.run(['xargs', '-r', '-0', third_party_path, '-z'],
            stdin='\0'.join(files) + '\0', stdout=subprocess.PIPE,
            check=True, universal_newlines=True)
        if "sought" in result.stdout:
            return False
        return True
    
    您会注意到我还切换到了
    subprocess.run()
    ,它在Python 3.5中可用+


    如果要重新实现
    xargs
    ,则需要找到内核常量
    ARG_MAX
    的值,并构建一个命令行列表,其大小永远不会超过此限制。然后,您可以在每次迭代后检查输出是否包含查找的
    ,如果包含,则立即退出。

    我通过在windows上使用临时文件解决了这个问题。对于Linux,命令可以按原样执行

    方法为不同的平台窗体生成完整命令:

    import tempfile
    
    temporary_file = 0
    def make_full_command(base_command, files):
        command = list(base_command)
    
        if platform.system() == "Windows":
            global temporary_file
            temporary_file = tempfile.NamedTemporaryFile()
            posix_files = map((lambda f: f.replace(os.sep, '/')),files)
            temporary_file.write(str.encode(" ".join(posix_files)))
            temporary_file.flush()
            command.append("@" + temporary_file.name)
        else:
            command.extend(files)
        return command
    
    将文件用作全局变量可确保在执行后将其清除


    通过这种方式,我不必为不同的操作系统找到最大命令长度

    我已经根据经验完成了这项工作(将参数分组并多次运行)。windows maxsize为32767,但不确定所有应用程序是否都支持该选项。第三方工具是否支持目录选项?在windows上,某些应用程序可以支持windows未扩展的通配符(*.txt)。这可以解决这个问题:这就是我正在使用的方法。问题是它使用固定数量的参数进行批处理,但这不能保证每个批处理的最终参数字符串长度,但我的答案中包含的方法应该考虑到这一点。如果最大值为10,并且您有13个参数,则第二批的大小将为3。或者你的意思是别的?是的,我的意思是测量所有参数字符串的长度之和。限制不是参数的数量,而是命令行的总大小。我看到了,我当时误解了。让我查一查。这应该是同样可能的。您仍然需要在每个参数中添加一个,因为操作系统级别上的类C表示需要在每个参数后添加一个零字节字符串终止符字节。您还必须考虑任何编码
    len('xargs是跨平台的吗?如果你的意思是它是否存在于Windows上,对不起,我不知道。
    -0
    选项是GNU扩展,因此你可能需要为其他POSIX平台进行调整,或者在另一个答案中使用解决方案,但这也需要一些调整,其中一些可能还依赖于系统。