¿Cómo inicio un comando externo?

Here's a summary of the ways to call external programs and the advantages and disadvantages of each: A continuación un resumen de las formas de llamar programas o comandos externos, y las ventajas y desventajas de cada uno de ellos:

1.- os.system("algun_comando con argumentos") pasa el comando y sus argumentos al shell de tu sistema. Esto es bueno porque puedes ejecutar múltiples comandos al mismo tiempo de esta forma, configurar pipes y redirecciones de entrada/salida. Por ejemplo, os.system("algun_comando < archivo_entrada | otro_comando > archivo_salida"). Sin embargo, a pesar de que es conveniente, tienes que manipular manualmente los caracteres de escape de tu shell, tales como espacios, etc. Por otro lado, esto también te deja ejecutar comandos que son simples comandos shell y no programas externos. vea la documentación

2.- stream = os.popen("algun_comando con argumentos") hará lo mismo que os.system excepto que te da un archivo tipo objeto que puedes usar para acceder a la entrada/salida de ese proceso. Hay otras 3 variantes de popen que manejan la e/s un poco diferente. Si pasas todo como un string, entonces tu comando es pasado al shell; si lo pasas como un list entonces no necesitas preocuparte por escapar nada.vea la documentación

3.- La clase Popen del módulo subprocess. This is intended as a replacement for os.popen but has the downside of being slightly more complicated by virtue of being so comprehensive. For example, you'd say


In [4]:
import subprocess
print subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE).stdout.read()


Hello World

en vez de...


In [5]:
import os
print os.popen("echo Hello World").read()


Hello World

Pero considero algo bueno tener todas las opciones unificadas en una clase, en vez de cuatro diferentes funciones popen. Vea la documentación

4.- La función call del módulo subprocess. Es básicamente igual que la clase Popen y usa los mismos argumentos, pero en su lugar, espera hasta que se complete el comando y te da un código de retorno Vea la documentación. Por ejemplo:


In [6]:
return_code = subprocess.call("echo Hello World", shell=True)  
print(return_code)


0

5.- El módulo os también tiene todas las funciones fork/exec/spawn que tendrías en un programa de C, pero no recomendaría usarlas directamente.

El módulo subprocess probablemente sea lo que debería usar. La ventaja de subprocess vs system es que es más flexible (tienes el stdout, stderr, el código "real" de estatus, un mejor manejo de errores, etc). Además, os.system fue desaprobado, o lo será:

http://docs.python.org/library/subprocess.html#replacing-older-functions-with-the-subprocess-module

Finalmente, por favor toma en cuenta que todos estos métodos el comando final es ejecutado por el shell como un string y eres responsable de escaparlo. Existen serias implicaciones de seguridad si alguna parte del string que pasas no puede ser confiado en su totalidad (por ejemplo, si un usuario introduce algún/alguna parte de el sring). Si es inseguro sólo usa este método con constantes. Para darte una idea, considera este código:


In [ ]:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()

e imagina que el usuario introduce "mi mami no me amaba && rm -rf /".


Créditos

Compilación de los mensajes de StackOverflow y 2, por Eli Courtwright y David Cournapeau, respectivamente.

Traducción: Espartaco Palma (@esparta)

Este obra está bajo una licencia Licencia Creative Commons Atribución 3.0.