我正在使用子进程模块中的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的最大长度,以便知道每次运行时要发送多少条路径。*
2条答案
按热度按时间wn9m85ua1#
如果传递shell=False,则Cmd.exe不起作用。
在Windows上,子进程将使用Win32 API中的CreateProcess函数创建新进程。此函数的documentation声明第二个参数(由subprocess.list2cmdline生成)的最大长度为32,768个字符,包括Unicode终止空字符。如果lpApplicationName为NULL,则lpCommandLine的模块名称部分限制为MAX_PATH字符。
对于您的示例,我建议为executable(args[0])提供一个值,并为第一个参数使用args。如果我对CreateProcess文档和子进程模块源代码的阅读是正确的,这应该可以解决您的问题。
[edit:在拿到Windows机器并进行测试后删除了args[1:]位]
ezykj2lf2#
对于类Unix平台,内核常量
ARG_MAX
是defined by POSIX.它至少需要4096字节,尽管在现代系统中,它可能是1兆字节或更多。在许多系统上,
getconf ARG_MAX
将在shell提示符下显示其值。shell实用程序
xargs
可以方便地分解一个长命令行。在大目录中失败,因为文件列表扩展为一个字节长度超过
ARG_MAX
的值,您可以使用类似下面的方法解决此问题(The选项
-0
是一个GNU扩展,但实际上是唯一完全安全的方式来明确地传递一个文件名列表,其中可能包含换行符、引用字符等。)解决这个限制的方法是,如果参数列表太长,它们会将其分开,并在命令行中多次运行
myscript.py
。根据myscript.py
的操作,这可能正是您想要的,也可能是灾难性的错误。(例如,如果它对传入的文件中的数字求和,则它处理的每组参数将得到多个结果。)相反,要将一长串参数传递给
subprocess.Popen()
和朋友,可以类似于...在大多数情况下,您可能应该避免使用原始的
Popen()
,而让run()
或check_call()
之类的 Package 函数来完成大部分工作:subprocess.run()
在Python 3.7及以后的版本中支持text=True
作为universal_newlines=True
的新名称。早于Python 3.5的版本没有run
,所以你需要回退到旧的遗留函数check_output
、check_call
或(很少)call
。如果你想在Python中重新实现
xargs
,可以这样做。与真实的的
xargs
一样,您需要对此函数返回的每个子列表运行一个单独的子进程。如果任何一个参数大于
ARG_MAX
,正确的实现应该会引发错误,但这只是一个快速演示。