2010-03-04 17 views
11

estoy usando Popen función del módulo de subproceso para ejecutar una herramienta de línea de comandos:¿Cuál es el subproceso.Popen max length of the args parameter?

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) 

La herramienta que estoy usando tiene una lista de archivos que se procesa. En algunos casos, esta lista de archivos puede ser muy larga. ¿Hay alguna manera de encontrar la longitud máxima que el parámetro args puede ser? Con un gran número de archivos que se pasa a la herramienta, estoy consiguiendo el error siguiente:

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 

¿Hay una manera general, para encontrar esta longitud máxima? Encontré el siguiente artículo en msdn: Command prompt (Cmd. exe) command-line string limitation pero no quiero codificar el valor. Prefiero obtener el valor en tiempo de ejecución para dividir el comando en varias llamadas.

estoy usando Python 2.6 en Windows XP 64.

Editar: añadiendo ejemplo de código

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

El problema se produce debido a que cada entrada real en la lista paths suele ser una ruta de archivo muy largo y hay son varios miles de ellos.

No me importa dividir el comando en varias llamadas al process_file.exe. Estoy buscando una forma general de obtener la longitud máxima que los argumentos pueden ser, así sé cuántas rutas enviar para cada ejecución.

+0

podría proporcionar un valor de ejemplo de lo que usted proporciona para args? –

+0

Llego bastante tarde a la fiesta, pero quiero agregar que recibí el mismo error debido a que la variable de entorno PATH se está volviendo demasiado larga después de agregar muchas entradas. – RedX

Respuesta

9

Si está pasando shell = False, entonces Cmd.exe no entra en juego.

En Windows, el subproceso utilizará la función CreateProcess de Win32 API para crear el nuevo proceso. El documentation para esta función indica que el segundo argumento (que se crea mediante subprocess.list2cmdline) tiene una longitud máxima de 32.768 caracteres, incluido el carácter nulo de terminación Unicode. Si lpApplicationName es NULL, la porción del nombre del módulo de lpCommandLine está limitada a MAX_PATH caracteres.

Dado su ejemplo, sugiero proporcionar un valor para el ejecutable (argumentos [0]) y usar argumentos para el primer parámetro. Si mi lectura de la documentación de CreateProcess y del código fuente del módulo de subproceso es correcta, esto debería resolver su problema.

[editar: se ha suprimido los args [1:] poco después de conseguir mis manos en una máquina Windows y pruebas]

+0

No estoy seguro si sigo su sugerencia sobre el uso de argumentos [1:] para el primer parámetro. He actualizado mi pregunta con un ejemplo de código. +1 para el enlace y consejo sobre CreateProcess –

+0

Intenté esto pero todavía estoy llegando a un límite: subprocess.Popen (cmd [1:] + paths, executable = cmd [0], stdout = subprocess.PIPE). Por ahora estoy usando 32000 como el límite para la longitud del comando y llamando a mi comando varias veces y recopilando todo el resultado. Me gustaría poder no tener el código 32000 codificado, pero obtener ese valor del medio ambiente. –

+0

Bueno, como se menciona en el documento que cité, el límite de 32768 está codificado en la primitiva CreateProcess (ese es el límite superior para enteros de 16 bits con signo, es decir, 2 ** 15). Como list2cmd agregará comillas y espacios al construir la línea de comando, alcanzará ese límite antes de que sum ([len (a) for a in args]) llegue a 2 ** 15. ¿No hay una forma de usar comodines para pasar tus argumentos al ejecutable?(los comodines generalmente son procesados ​​por el ejecutable bajo Windows) –

Cuestiones relacionadas