args参数的subprocess.Popen max length是什么?

2024-04-27 03:40:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用子流程模块中的Popen函数执行命令行工具:

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

我正在使用的工具将获取一个文件列表,然后对其进行处理。在某些情况下,此文件列表可能非常长。有没有办法找到args参数的最大长度?随着大量文件被传递到工具,我得到以下错误:

Traceback (most recent call last):
  File "dump_output_sopuids.py", line 68, in <module>
    uid_map = create_sopuid_to_path_dict_dcmdump(dicom_files)
  File "dump_output_sopuids.py", line 41, in create_sopuid_to_path_dict_dcmdump
    dcmdump_output = subprocess.Popen(cmd,stdout=subprocess.PIPE).communicate(0)[0]
  File "c:\python26\lib\subprocess.py", line 621, in __init__
    errread, errwrite)
  File "c:\python26\lib\subprocess.py", line 830, in _execute_child
    startupinfo)
WindowsError: [Error 206] The filename or extension is too long

有没有找到这个最大长度的通用方法?我在msdn上找到了以下文章:Command prompt (Cmd. exe) command-line string limitation,但我不想在值中硬编码。我宁愿在运行时获取该值,以便将命令分解为多个调用。

我在Windows XP 64上使用Python 2.6。

编辑:添加代码示例

paths = ['file1.dat','file2.dat',...,'fileX.dat']
cmd = ['process_file.exe','+p'] + paths
cmd_output = subprocess.Popen(cmd,stdout=subprocess.PIPE).communicate(0)[0]

出现此问题的原因是paths列表中的每个实际条目通常是一个很长的文件路径,并且有数千个。

我不介意将命令分解为对process_file.exe的多个调用。我正在寻找一种通用的方法来获取args的最大长度,这样我就知道每次运行要发送多少条路径。


Tags: 文件工具inpycmdnonefalse列表
2条回答

对于类Unix平台,内核常量ARG_MAXdefined by POSIX.,它至少需要4096字节,尽管在现代系统上,它可能是1兆字节或更多。

在许多系统中,getconf ARG_MAX将在shell提示符处显示其值。

shell实用程序xargs方便地允许您分解一个长命令行。例如,如果

python myscript.py *

在大目录中失败,因为文件列表扩展到长度(字节)超过ARG_MAX的值,您可以使用

printf '%s\0' * |
xargs -0 python myscript.py

(选项-0是一个GNU扩展名,但实际上是唯一一种完全安全的方法,可以毫不含糊地传递可能包含换行符、引用字符等的文件名列表)也可以探索

find . -maxdepth 1 -type f -exec python myscript.py {} +

相反,将一长串参数传递给subprocess.Popen()和朋友,类似于

p = subprocess.Popen(['xargs', '-0', 'command'],
    stdin=subprocess.PIPE, stdout=subprocess.PIPE,
    stderr=subprocess.PIPE)
out, err = p.communicate('\0'.join(long_long_argument_list))

。。。在大多数情况下,您可能应该避免原始的Popen(),并让像run()check_call()这样的包装函数完成大部分工作:

r = subprocess.run(['xargs', '-0', 'command'],
    input='\0'.join(long_long_argument_list),
    universal_newlines=True)
out = r.stdout

subprocess.run()支持3.7+中的text=True作为universal_newlines=True的新名称。早于3.5的Python版本没有run,因此您需要返回到旧的遗留函数check_outputcheck_call,或者(很少)返回到call

如果传递的是shell=False,则Cmd.exe不起作用。

在windows上,子进程将使用Win32 API中的create process函数来创建新进程。此函数的documentation声明第二个参数(由subprocess.list2cmdline生成)的最大长度为32768个字符,包括以Unicode结尾的空字符。如果lpApplicationName为空,lpCommandLine的模块名部分将限制为最大路径字符。

根据您的示例,我建议为可执行文件(args[0])提供一个值,并将args用作第一个参数。如果我对CreateProcess文档和子流程模块源代码的阅读是正确的,那么这应该可以解决您的问题。

[编辑:在接触windows计算机并进行测试后删除了args[1:]位]

相关问题 更多 >