【问题标题】:Is Python 'sys.argv' limited in the maximum number of arguments?Python 'sys.argv' 的最大参数数量是否受到限制?
【发布时间】:2012-02-24 13:23:45
【问题描述】:

我有一个需要处理大量文件的 Python 脚本。为了绕过 Linux 对可传递给命令的参数数量的相对较小的限制,我将find -print0xargs -0 结合使用。

我知道另一种选择是使用 Python 的 glob 模块,但是当我有更高级的 find 命令、查找修改时间等时,这将无济于事。

在大量文件上运行我的脚本时,Python 只接受参数的子集,我最初认为是在 argparse 中的一个限制,但似乎在 sys.argv 中。我找不到任何关于此的文档。是bug吗?

这里有一个示例 Python 脚本来说明这一点:

import argparse
import sys
import os

parser = argparse.ArgumentParser()
parser.add_argument('input_files', nargs='+')
args = parser.parse_args(sys.argv[1:])

print 'pid:', os.getpid(), 'argv files', len(sys.argv[1:]), 'argparse files:', len(args.input_files)

我有很多文件要运行它:

$ find ~/ -name "*" -print0 | xargs -0 ls > filelist
748709 filelist

但似乎xargs 或 Python 正在对我的大文件列表进行分块并使用几个不同的 Python 运行对其进行处理:

$ find ~/ -name "*" -print0 | xargs -0 python test.py
pid: 4216 argv files 1819 number of files: 1819
pid: 4217 argv files 1845 number of files: 1845
pid: 4218 argv files 1845 number of files: 1845
pid: 4219 argv files 1845 number of files: 1845
pid: 4220 argv files 1845 number of files: 1845
pid: 4221 argv files 1845 number of files: 1845
...

为什么要创建多个进程来处理列表?为什么它被分块?我认为文件名中没有换行符,-print0-0 不应该处理这个问题吗?如果有换行符,我希望sed -n '1810,1830p' filelist 对上面的例子表现出一些奇怪。什么给了?

我差点忘了:

$ python -V
Python 2.7.2+

【问题讨论】:

  • 奇怪的问题。作为另一种选择,您当然可以在脚本中解析 filelist
  • 这就是 xargs 所做的。它仍然需要通过 shell 调用 Python,因此对参数有相同的限制。为什么不让你的 Python 程序直接接受 ~/-name * 参数呢?
  • 我曾认为 xargs 以某种方式神奇地解决了有限参数空间问题。事实证明,它只是用较小的块分叉了一个单独的进程。事实证明,这种行为在我使用 xargs 的每个应用程序中都没有区别,保存这个......

标签: python xargs argparse argv


【解决方案1】:

Python 似乎没有限制参数的数量,但操作系统有。

查看here 以获得更全面的讨论。

【讨论】:

    【解决方案2】:

    xargs 将尽可能多地通过,但仍有限制。例如,

    find ~/ -name "*" -print0 | xargs -0 wc -l | grep total
    

    会给你多行输出。

    您可能希望脚本获取包含文件名列表的文件,或者在其标准输入中接受文件名。

    【讨论】:

      【解决方案3】:

      xargs 默认会分块你的参数。查看xargs--max-args--max-chars 选项。它的手册页还解释了限制(在--max-chars 下)。

      【讨论】:

      • 谢谢。我以前没见过这个。知道为什么上面的命令find ~/ -name "*" -print0 | xargs -0 ls > filelist 真的有效吗?似乎ls 将被调用多次,所有写入(而不是附加!)到同一个文件。也许文件只打开一次,我们捕获的是 xargs 的输出?
      • shell 负责重定向。 ls 实际上输出到stdout。将其视为括号内的行上的所有内容和外面的重定向。
      【解决方案4】:

      find 提供您想要的一切,os.walk 提供。

      不要使用 find 和 shell 来做任何事情。

      使用os.walk 并用 Python 编写所有规则和过滤器。

      “寻找修改时间”意味着您将使用os.stat 或一些类似的库函数。

      【讨论】:

      • 我原则上同意在 python 中做这一切是要走的路,使用 os.walk、glob.glob 和 os.stat。我不知道的是 xargs 仍然遵守 os 限制,只是使用剩余的参数多次调用命令。
      • “原则上同意”的意思是“不同意”。然而,你没有提供任何理由。以下是您的决定全是建议的原因。所有的 Python 都更快、更简单、更灵活。更简单,因为它是一种语言:Python。更快,因为它全部在一个进程中运行(无需交换)。如果您想要更快的速度,请使用multiprocessing。最后,它更加灵活,因为您不受find 的奇怪限制的限制。简化您的应用程序没有缺点。
      • 应用程序通常不需要处理数千个文件。这项工作通常在几十个文件(染色体)上完成;在我正在测试的特定基准测试中,我有数千个文件。也许我的 OP 没有说清楚。
      • @JakeBiesinger:也许我的评论没有说明find 在处理一个或数百万个文件时仍然是个坏主意。我不会重复这些原因,而是说用 Python 替换基于 find 的 shell 脚本没有任何不利之处。没有缺点。众多优势。
      • ofc 有一个缺点,你用额外的逻辑使你的脚本复杂化。而不是对文件执行任何操作,现在它还处理如何遍历文件系统。 find 非常强大,并且已经做得非常好
      【解决方案5】:

      问题在于 xargs is limited 由调用参数的字符数决定(最多 2091281)。

      快速测试表明,根据路径的长度,该范围从 5000 个文件到 55000 个文件。

      获得更多的解决方案是通过标准输入来接受文件路径中的管道。

      find ... -print0 | script.py

      #!/usr/bin/env python3
      
      import sys
      
      files = sys.stdin.read().split('\0')
      ...
      
      

      【讨论】:

        猜你喜欢
        • 2016-06-06
        • 2014-02-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-30
        • 1970-01-01
        相关资源
        最近更新 更多