4370 votos

Llamando a un comando externo en Python

¿Cómo puedo llamar a un comando externo (como si yo la hubiera escrito en la shell de Unix o símbolo del sistema de Windows) desde dentro de una secuencia de comandos de Python?

4199voto

David Cournapeau Puntos 21956

Buscar en el módulo subprocess en la stdlib:

from subprocess import call
call(["ls", "-l"])

La ventaja de subproceso vs sistema es que es más flexible (se puede obtener el stdout, stderr, "el verdadero" código de estado, un mejor control de errores, etc...). Creo que os.system está en desuso, demasiado, o va a ser:

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

Para un rápido/sucio/una hora de secuencias de comandos, os.system es suficiente, sin embargo.

2811voto

Eli Courtwright Puntos 53071

He aquí un resumen de las maneras de llamar a programas externos y las ventajas y desventajas de cada uno:

  1. os.system("some_command with args") pasa el comando y los argumentos para su sistema de concha. Esto es bueno porque en realidad se puede ejecutar varios comandos a la vez, de esta manera, y establecer las tuberías de entrada y/redirección de la salida. Por ejemplo,
    os.system("some_command < input_file | another_command > output_file")
    Sin embargo, aunque esto es conveniente, usted tiene que manejar manualmente el escape de la concha de caracteres, tales como espacios, etc. Por otro lado, esto también le permite ejecutar los comandos que son simplemente comandos de la shell y en realidad no programas externos.
    ver documentación

  2. stream = os.popen("some_command with args") hará lo mismo como os.system salvo que se le da a un archivo-como objeto que puede utilizar para tener acceso estándar de entrada/salida para ese proceso. Hay otras 3 variantes de popen que manejar la e/s de forma ligeramente diferente. Si pasa todo como una cadena, entonces su orden se pasa a la concha; si usted pasa en una lista, a continuación, usted no necesita preocuparse acerca de escapar de nada.
    ver documentación

  3. La Popen clase de la subprocess módulo. Esto está pensado como un reemplazo para os.popen , pero tiene la desventaja de ser un poco más complicado por el hecho de ser tan comprensivo. Por ejemplo, usted diría que :

    print subprocess.Popen("echo Hello World", shell=True, stdout=PIPE).stdout.read()
    

    en lugar de

    print os.popen("echo Hello World").read()
    

    pero es bueno tener todas las opciones en una sola clase en lugar de 4 diferentes popen funciones.
    ver documentación

  4. La call de la función del subprocess módulo. Esto es básicamente igual que el Popen de clase y se lleva a todos de la misma argumentos, sino simplemente espera hasta que se complete el comando y te da el código de retorno. Por ejemplo:

    return_code = subprocess.call("echo Hello World", shell=True)  
    

    ver documentación

  5. El sistema operativo del módulo también tiene todas las fork/exec/spawn funciones que te gustaría tener en un programa en C, pero no recomiendo el uso de ellos directamente.

La subprocess módulo debe probablemente lo que usted use.

Finalmente tenga en cuenta que para todos los métodos para pasar el último comando a ser ejecutado por el intérprete de comandos como una cadena y usted es responsable de escapar de ella hay serias implicaciones de seguridad si cualquier parte de la cadena que se le pasa no puede ser de plena confianza (por ejemplo, si un usuario está introduciendo algunos/de cualquier parte de la cadena). Si no estás seguro de que sólo el uso de estos métodos con constantes. Para dar una idea de las implicaciones de considerar este código

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

e imaginemos que el usuario entra en "mi mama no me amas && rm-rf /".

310voto

EmmEff Puntos 1789

Yo normalmente uso:

import subprocess

p = subprocess.Popen('ls', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in p.stdout.readlines():
    print line,
retval = p.wait()

Eres libre de hacer lo que quiera con el stdout datos en la tubería. De hecho, usted puede simplemente omitir los parámetros (stdout= y stderr=) y se comportan como os.system().

200voto

newtover Puntos 12301

Algunos consejos de separar al niño de proceso de la llamada a uno (comenzando el proceso hijo en el fondo).

Suponga que desea iniciar una larga tarea de un script CGI, que es el proceso hijo debe vivir más que la CGI-script de proceso de ejecución.

El ejemplo clásico de la subproceso módulo docs es:

import subprocess
import sys

# some code here

pid = subprocess.Popen([sys.executable, "longtask.py"]) # call subprocess

# some more code here

La idea aquí es que usted no quiere esperar en la línea de 'call subproceso " hasta el longtask.py está terminado. Pero no está claro qué sucede después de la línea " algunas de las más código aquí " desde el ejemplo.

Mi objetivo de la plataforma era de freebsd, pero el desarrollo fue en windows, así que me enfrentaba al problema en windows por primera vez.

En windows (win xp), el proceso padre no va a terminar hasta que el longtask.py ha terminado su trabajo. No es lo que quiere en la CGI-script. El problema no es específico para Python, PHP en la comunidad de los problemas son los mismos.

La solución es pasar DETACHED_PROCESS bandera subyacentes a la función CreateProcess en win API. Si de casualidad tienes instalado pywin32 puede importar la bandera de la win32process módulo, de lo contrario debe definir usted mismo:

DETACHED_PROCESS = 0x00000008

pid = subprocess.Popen([sys.executable, "longtask.py"],
                       creationflags=DETACHED_PROCESS).pid

En freebsd tenemos otro problema: cuando el proceso padre se acaba, se termina el hijo de los procesos. Y eso no es lo que quiere en la CGI-script. Algunos experimentos mostraron que el problema parecía estar en el intercambio de sys.stdout. Y la solución de trabajo fue el siguiente:

pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)

No he comprobado el código en otras plataformas y no sabemos las razones del comportamiento en freebsd. Si alguien sabe, por favor, comparte tus ideas. Buscando en google sobre el inicio de los procesos de fondo en Python no arroja luz todavía.

124voto

SirWart Puntos 627

Me gustaría recomendar el uso del módulo subprocess en lugar de os.system porque shell escape para usted y por lo tanto es mucho más seguro: http://docs.python.org/library/subprocess.html

subprocess.call(['ping', 'localhost'])

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X