Pregunta Llamar a un comando externo en Python


¿Cómo puedo llamar a un comando externo (como si lo hubiese escrito en el shell de Unix o en el símbolo del sistema de Windows) desde un script de Python?


3622
2017-09-18 01:35


origen


Respuestas:


Mira el módulo de subproceso en la biblioteca estándar:

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

La ventaja de subproceso vs. sistema es que es más flexible (puede obtener stdout, stderr, el código de estado "real", un mejor manejo de errores, etc.).

los documentación oficial recomienda el subproceso módulo sobre el sistema alternativo os ():

los subproceso el módulo proporciona instalaciones más potentes para generar nuevos procesos y recuperar sus resultados; usar ese módulo es preferible a usar esta función [os.system()]

Los "Reemplazo de funciones anteriores con el módulo de subproceso"sección en el subproceso la documentación puede tener algunas recetas útiles.

Documentación oficial sobre subproceso módulo:


3491
2017-09-18 01:39



Aquí hay un resumen de las formas de llamar a los programas externos y las ventajas y desventajas de cada uno:

  1. os.system("some_command with args") pasa el comando y los argumentos al shell de tu sistema. Esto es bueno porque en realidad puede ejecutar varios comandos a la vez de esta manera y configurar las canalizaciones y la redirección de entrada / salida. Por ejemplo:

    os.system("some_command < input_file | another_command > output_file")  
    

    Sin embargo, si bien es conveniente, debe manejar manualmente el escape de caracteres de shell, como espacios, etc. Por otro lado, esto también le permite ejecutar comandos que son simplemente comandos de shell y no programas en realidad externos. Ver la documentación.

  2. stream = os.popen("some_command with args") hará lo mismo que os.system excepto que le proporciona un objeto similar a un archivo que puede usar para acceder a la entrada / salida estándar para ese proceso. Hay otras 3 variantes de popen que manejan la E / S de forma ligeramente diferente. Si pasa todo como una cadena, su comando pasa al shell; si los pasa como una lista, entonces no necesita preocuparse por escapar de nada. Ver la documentación.

  3. los Popen clase del subprocess módulo. Esto está pensado como un reemplazo para os.popen pero tiene el inconveniente de ser un poco más complicado en virtud de ser tan completo. Por ejemplo, dirías:

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

    en lugar de:

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

    pero es bueno tener todas las opciones allí en una clase unificada en lugar de 4 funciones popen diferentes. Ver la documentación.

  4. los call función de la subprocess módulo. Esto es básicamente como el Popen clase y toma todos los mismos argumentos, pero simplemente espera hasta que el comando finalice y le proporciona el código de retorno. Por ejemplo:

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

    Ver la documentación.

  5. Si usa Python 3.5 o posterior, puede usar el nuevo subprocess.run función, que es muy similar a la anterior, pero aún más flexible y devuelve una CompletedProcess objeto cuando el comando termina de ejecutarse.

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

los subprocess módulo probablemente debería ser lo que usa.

Finalmente, tenga en cuenta que para todos los métodos en los que pase el comando final, el shell lo ejecutará como una cadena y usted será responsable de escapar de él. Hay serias implicaciones de seguridad si cualquier parte de la cadena que pase no puede ser completamente confiable. Por ejemplo, si un usuario está ingresando alguna / parte de la cadena. Si no está seguro, solo use estos métodos con constantes. Para darle una pista de las implicaciones considere este código:

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

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


2466
2017-09-18 13:11



Yo suelo usar:

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 quieras con el stdout datos en la tubería. De hecho, puede simplemente omitir esos parámetros (stdout= y stderr=) y se comportará como os.system().


255
2017-09-18 18:20



Algunos consejos sobre cómo separar el proceso secundario del que llama (iniciando el proceso secundario en el fondo).

Supongamos que desea iniciar una tarea larga desde una secuencia de comandos CGI, es decir, el proceso hijo debe durar más que el proceso de ejecución de scripts CGI.

El ejemplo clásico de los documentos del módulo de subproceso 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 no desea esperar en la línea 'call subprocess' hasta que longtask.py haya terminado. Pero no está claro qué sucede después de la línea 'aquí más código' del ejemplo.

Mi plataforma de destino era freebsd, pero el desarrollo estaba en Windows, así que primero me enfrenté al problema de Windows.

En windows (win xp), el proceso principal no finalizará hasta que longtask.py haya terminado su trabajo. No es lo que quieres en CGI-script. El problema no es específico de Python, en la comunidad PHP los problemas son los mismos.

La solución es pasar DETACHED_PROCESS Bandera de creación de proceso a la función CreateProcess subyacente en win API. Si por casualidad ha instalado pywin32, puede importar el indicador desde el módulo win32process; de lo contrario, debe definirlo usted mismo:

DETACHED_PROCESS = 0x00000008

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

/ * UPD 2015.10.27 @eryksun en un comentario a continuación señala que el indicador semánticamente correcto es CREATE_NEW_CONSOLE (0x00000010) * /

En freebsd tenemos otro problema: cuando el proceso principal finaliza, también termina el proceso hijo. Y eso tampoco es lo que quieres en CGI-script. Algunos experimentos mostraron que el problema parecía estar en compartir sys.stdout. Y la solución de trabajo fue la 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 sé las razones del comportamiento en freebsd. Si alguien sabe, comparte tus ideas. Buscar en Google al iniciar procesos en segundo plano en Python aún no arroja ninguna luz.


157
2018-02-12 10:15



Recomiendo usar el módulo de subproceso en lugar de os.system porque hace que Shell escape para usted y, por lo tanto, es mucho más seguro: http://docs.python.org/library/subprocess.html

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

97
2017-09-18 01:42



import os
cmd = 'ls -al'
os.system(cmd)

Si desea devolver los resultados del comando, puede usar os.popen. Sin embargo, esto está en desuso desde la versión 2.6 a favor de la módulo de subproceso, que otras respuestas han cubierto bien.


93
2017-09-18 01:37



import os
os.system("your command")

Tenga en cuenta que esto es peligroso, ya que el comando no se limpia. Dejo que sea usted quien busque la documentación relevante en los módulos 'os' y 'sys'. Hay muchas funciones (exec * y spawn *) que harán cosas similares.


82
2017-09-18 01:37



Yo siempre uso fabric para esto, cosas como:

from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )

Pero esta parece ser una buena herramienta: sh (Interfaz del subproceso de Python).

Mira un ejemplo:

from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)

51
2018-03-13 00:12



Consulte la biblioteca de Python "pexpect" también.

Permite el control interactivo de programas / comandos externos, incluso ssh, ftp, telnet, etc. Puede escribir algo así como:

child = pexpect.spawn('ftp 192.168.0.24')

child.expect('(?i)name .*: ')

child.sendline('anonymous')

child.expect('(?i)password')

51
2017-10-07 07:09



Hay muchas bibliotecas diferentes que le permiten llamar comandos externos con Python. Para cada biblioteca he dado una descripción y he mostrado un ejemplo de invocación de un comando externo. El comando que utilicé como ejemplo es ls -l (liste todos los archivos). Si desea obtener más información sobre cualquiera de las bibliotecas que he enumerado y vinculado la documentación para cada una de ellas.

Fuentes:

Estas son todas las bibliotecas:

Espero que esto te ayude a tomar una decisión sobre qué biblioteca usar :)

subproceso

El subproceso le permite llamar a comandos externos y conectarlos a sus canalizaciones de entrada / salida / error (stdin, stdout y stderr). El subproceso es la opción predeterminada para ejecutar comandos, pero a veces otros módulos son mejores.

subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command

os

os se usa para "funcionalidad dependiente del sistema operativo". También se puede usar para llamar comandos externos con os.system y os.popen (Nota: También hay un subproceso.popen). os siempre ejecutará el shell y es una alternativa simple para las personas que no necesitan o no saben cómo usar subprocess.run.

os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output

sh

sh es una interfaz de subproceso que le permite llamar a los programas como si fueran funciones. Esto es útil si desea ejecutar un comando varias veces.

sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function

plomo

plumbum es una biblioteca para programas Python "tipo script". Puede llamar a programas como funciones como en sh. Plumbum es útil si desea ejecutar una tubería sin el shell.

ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command

pexpect

pexpect te permite generar aplicaciones para niños, controlarlas y encontrar patrones en sus resultados. Esta es una mejor alternativa al subproceso para comandos que esperan un tty en Unix.

pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo [email protected]:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')

tela

fabric es una biblioteca Python 2.5 y 2.7. Le permite ejecutar comandos de shell locales y remotos. Fabric es una alternativa simple para ejecutar comandos en un shell seguro (SSH)

fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output

enviado

el enviado se conoce como "subproceso para humanos". Se utiliza como una envoltura de conveniencia alrededor del subprocess módulo.

r = envoy.run("ls -l") # Run command
r.std_out # get output

comandos

commands contiene funciones de envoltura para os.popen, pero se ha eliminado de Python 3 desde subprocess es una mejor alternativa

La edición se basó en el comentario de J.F. Sebastian.


46
2017-10-29 14:02