2011-07-09 11 views
5

Parece que no recibo el código de salida correcto de subprocess.call en Windows.Código de salida incorrecto en python al llamar a la secuencia de comandos de Windows

import subprocess 
exit_code = subprocess.call(['ant.bat', 'fail']) 
print exit_code # prints 0 

Hacer lo mismo en las ventanas parece volver algo distinto de 0

> echo %errorlevel% 
0 
> ant fail 
> echo %errorlevel% 
1 

¿No deberían los valores de ambas llamadas dar el mismo valor? ¿Estoy haciendo algo mal?

En el peor de los casos, ¿cómo puedo verificar el valor de% errorlevel% en mi secuencia de comandos python?

ACTUALIZACIÓN:

Probé algo como esto para obtener el valor errorlevel:

environment = os.environment.copy() 
cmd = subprocess.Popen(['ant.bat', 'fail'], env = environment) 
for key, value in environment.items(): 
    print '%s = %s' % (key, value) 

Sin embargo, no veo nivel de error en ese diccionario (os.getenv [ 'nivel de error'] también falla).

+0

Tu código funciona para mí (en Windows 7). ¿Puedes darnos más detalles? ¿Puede ser que el problema esté en el archivo .bat en sí? – Michael

Respuesta

7

un código de salida de proceso y la variable de entorno errorlevel no son lo mismo:

ant.bat: 

if "%1"=="batch_fail" exit /B 1 
if "%1"=="proc_fail" exit 1 


>>> import subprocess 
>>> subprocess.call(['ant.bat', 'batch_fail']) 
0 
>>> subprocess.call(['ant.bat', 'proc_fail']) 
1 

batch_fail fijará el errorlevel a 1, pero que ya no es disponible después de salir de la cáscara. proc_fail, sin embargo, establece el código de salida del proceso a 1. La única solución que viene a la mente es un archivo por lotes que llama envoltorio ant.bat y establece el código de salida del proceso de acuerdo con el nivel de error:

ant_wrapper.bat: 

@echo off 
call ant.bat %1 
if errorlevel 1 exit 1 

>>> subprocess.call(['ant_wrapper.bat']) 
0 
>>> subprocess.call(['ant_wrapper.bat', 'batch_fail']) 
1 
>>> subprocess.call(['ant_wrapper.bat', 'proc_fail']) 
1 

Edición:

Su actualización me hizo pensar en un enfoque alternativo con Popen. Puede ejecutar el archivo por lotes mediante la opción cmd/K, que ejecutará un comando sin salir. Entonces sólo tiene que enviar a través de la entrada estándar exit %errorlevel%, y comunicar():

#test errorlevel==1 
>>> p = subprocess.Popen(['cmd', '/K', 'ant.bat', 'batch_fail'], 
     stdin=subprocess.PIPE, stdout=subprocess.PIPE) 
>>> stdoutdata, stderrdata = p.communicate(b'exit %errorlevel%\r\n') 
>>> p.returncode 
1 

#test errorlevel==0 
>>> p = subprocess.Popen(['cmd', '/K', 'ant.bat'], 
     stdin=subprocess.PIPE, stdout=subprocess.PIPE) 
>>> stdoutdata, stderrdata = p.communicate(b'exit %errorlevel%\r\n') 
>>> p.returncode 
0 
+0

Gracias por esa información. Entonces, ¿crees que puedo obtener el valor de% errorlevel% con Popen? Por favor vea mi actualización a la pregunta original. Publiqué mi intento de usar Popen. ¿Puedo hacer que funcione de alguna manera? –

+0

Gracias que funciona. ¿Hay alguna manera de hacer lo mismo sin redireccionar sin embargo? Quiero seguir imprimiendo la salida a la consola, pero eliminar stdout = PIPE resulta en todo tipo de locura para mí (a veces termino teniendo que cerrar toda la ventana de la terminal). –

-1

os.system('ant.bat fail') hace exactamente lo que quiere. Devuelve el nivel de error.

0

que era capaz de conseguir el comportamiento correcto utilizando el lote call command, como

cmd = [os.environ['COMSPEC'], '/c', 'call', bat_file] 
try: 
    subprocess.check_call(cmd) 
except subprocess.CalledProcessError: 
    # Error handling code 

(utilicé subprocess.check_call pero subprocess.call se debe trabajar de la misma manera).

También es siempre una buena idea colocar if errorlevel 1 exit 1 después de cada comando en su secuencia de comandos por lotes, para propagar los errores (aproximadamente el equivalente a set -e de bash).

Cuestiones relacionadas