Llamar a un comando externo desde Python


4886

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

Respuestas:


4696

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

import subprocess
subprocess.run(["ls", "-l"])

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

La documentación oficial recomienda el subprocessmódulo sobre la alternativa os.system():

El subprocessmó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()].

La Reemplazo de funciones antiguas con la sección Módulo de subproceso en la subprocessdocumentación puede tener algunas recetas útiles.

Para versiones de Python anteriores a 3.5, use call:

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

¿Hay alguna manera de usar la sustitución de variables? IE traté de hacer echo $PATHusando call(["echo", "$PATH"]), pero solo hizo eco de la cadena literal en $PATHlugar de hacer cualquier sustitución. Sé que podría obtener la variable de entorno PATH, pero me pregunto si hay una manera fácil de hacer que el comando se comporte exactamente como si lo hubiera ejecutado en bash.
Kevin Wheeler

@KevinWheeler Tendrás que usar shell=Truepara que eso funcione.
SethMMorton

39
@KevinWheeler NO debe usar shell=True, para este propósito Python viene con os.path.expandvars . En su caso se puede escribir: os.path.expandvars("$PATH"). @SethMMorton, reconsidere su comentario -> ¿Por qué no usar shell = True
Murmel

¿bloquea la llamada? es decir, si quiero ejecutar varios comandos en un forbucle, ¿cómo lo hago sin que bloquee mi script de Python? No me importa la salida del comando, solo quiero ejecutar muchos de ellos.
Charlie Parker

55
Si desea crear una lista a partir de un comando con parámetros , una lista que se puede usar con subprocesscuándo shell=False, luego use shlex.splitpara una manera fácil de hacerlo docs.python.org/2/library/shlex.html#shlex.split
Daniel F

2985

Aquí hay un resumen de las formas 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 al shell de su sistema. Esto es bueno porque en realidad puede ejecutar múltiples comandos a la vez de esta manera y configurar tuberías y redirección de entrada / salida. Por ejemplo:

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

Sin embargo, aunque esto 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 externos. Ver la documentación .

  1. stream = os.popen("some_command with args")hará lo mismo, os.systemexcepto 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 se pasa al shell; si los pasa como una lista, entonces no necesita preocuparse por escapar de nada. Ver la documentación .

  2. La Popenclase del subprocessmódulo. Esto pretende ser un reemplazo os.popenpero tiene la desventaja 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 vez 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 .

  3. La callfunción del subprocessmódulo. Esto es básicamente como la Popenclase y toma todos los mismos argumentos, pero simplemente espera hasta que el comando se complete y le dé el código de retorno. Por ejemplo:

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

    Ver la documentación .

  4. Si está en Python 3.5 o posterior, puede usar la nueva subprocess.runfunción, que es muy parecida a la anterior pero aún más flexible y devuelve un CompletedProcessobjeto cuando el comando termina de ejecutarse.

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

El subprocessmódulo probablemente debería ser lo que usa.

Finalmente, tenga en cuenta que para todos los métodos en los que pasa el comando final para que el shell lo ejecute como una cadena y usted es responsable de escapar de él. Existen serias implicaciones de seguridad si no se puede confiar completamente en alguna parte de la cadena que pasa. Por ejemplo, si un usuario está ingresando alguna / cualquier 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 imagine que el usuario ingresa algo "mi mamá no me amaba && rm -rf /" que podría borrar todo el sistema de archivos.


22
Buena respuesta / explicación. ¿Cómo justifica esta respuesta el lema de Python como se describe en este artículo? fastcompany.com/3026446/… "Estilísticamente, Perl y Python tienen filosofías diferentes. Los lemas más conocidos de Perl son" Hay más de una forma de hacerlo ". Python está diseñado para tener una forma obvia de hacerlo" Parece que debería ser ¡La otra manera! En Perl, conozco solo dos formas de ejecutar un comando: usar back-tick o open.
Jean

12
Si usa Python 3.5+, use subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run
phoenix

44
Lo que normalmente se necesita saber es qué se hace con STDOUT y STDERR del proceso secundario, porque si se ignoran, en algunas condiciones (bastante comunes), eventualmente el proceso secundario emitirá una llamada del sistema para escribir en STDOUT (¿STDERR también?) eso excedería el búfer de salida proporcionado por el sistema operativo para el proceso, y el sistema operativo hará que se bloquee hasta que algún proceso lea de ese búfer. Entonces, con las formas recomendadas actualmente subprocess.run(..), ¿qué hace exactamente ? Esto no captura stdout o stderr de manera predeterminada. ¿implicar? ¿Qué pasa con subprocess.check_output(..)STDERR?
Evgeni Sergeev

2
@Pitto sí, pero eso no es lo que se ejecuta con el ejemplo. Observe el echofrente de la cadena pasada a Popen? Entonces el comando completo será echo my mama didnt love me && rm -rf /.
Chris Arndt

66
Esto es posiblemente el camino equivocado. La mayoría de las personas solo necesitan subprocess.run()o sus hermanos mayores subprocess.check_call()et al. Para los casos en que estos no son suficientes, vea subprocess.Popen(). os.popen()tal vez no debería mencionarse en absoluto, o incluso después de "piratear su propio código fork / exec / spawn".
tripleee

358

Implementación típica:

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()

Usted es libre de hacer lo que quiera con los stdoutdatos en la tubería. De hecho, simplemente puede omitir esos parámetros ( stdout=y stderr=) y se comportará como os.system().


44
.readlines()lee todas las líneas a la vez, es decir, bloquea hasta que sale el subproceso (cierra el extremo de la tubería). Para leer en tiempo real (si no hay problemas de almacenamiento en búfer) puede:for line in iter(p.stdout.readline, ''): print line,
jfs

1
¿Podría explicar qué quiere decir con "si no hay problemas de almacenamiento en búfer"? Si el proceso se bloquea definitivamente, la llamada del subproceso también se bloquea. Lo mismo podría suceder con mi ejemplo original también. ¿Qué más podría pasar con respecto al almacenamiento en búfer?
EmmEff

15
el proceso hijo puede usar el almacenamiento en bloque en modo no interactivo en lugar del almacenamiento en línea, por lo que p.stdout.readline()(nota: no sal final) no verá ningún dato hasta que el hijo llene su almacenamiento intermedio. Si el niño no produce muchos datos, la salida no será en tiempo real. Vea la segunda razón en P: ¿Por qué no usar una tubería (popen ())? . En esta respuesta se proporcionan algunas soluciones (pexpect, pty, stdbuf)
jfs

44
el problema del almacenamiento en búfer solo es importante si desea la salida en tiempo real y no se aplica a su código que no imprime nada hasta que se reciben todos los datos
jfs

3
Esta respuesta estuvo bien para su tiempo, pero ya no deberíamos recomendarla Popenpara tareas simples. Esto también especifica innecesariamente shell=True. Prueba una de las subprocess.run()respuestas.
tripleee

230

Algunas sugerencias para separar el proceso hijo del que llama (iniciando el proceso hijo en segundo plano).

Suponga que desea comenzar una tarea larga desde un script CGI. Es decir, el proceso secundario debería vivir más tiempo que el proceso de ejecución del script CGI.

El ejemplo clásico de la documentación 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 'llamar subproceso' hasta que finalice longtask.py. Pero no está claro qué sucede después de la línea 'más código aquí' del ejemplo.

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

En Windows (Windows XP), el proceso padre no finalizará hasta que longtask.py haya finalizado su trabajo. No es lo que quieres en un script CGI. El problema no es específico de Python; En la comunidad PHP, los problemas son los mismos.

La solución es pasar DETACHED_PROCESS Indicador de creación de procesos a la función CreateProcess subyacente en la API de Windows. Si tiene instalado pywin32, puede importar el indicador desde el módulo de proceso win32, 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 2015.10.27 @eryksun en un comentario debajo de las notas, que el indicador semánticamente correcto es CREATE_NEW_CONSOLE (0x00000010) * /

En FreeBSD tenemos otro problema: cuando el proceso padre finaliza, también finaliza los procesos hijos. Y eso tampoco es lo que quieres en un script CGI. 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é los motivos del comportamiento en FreeBSD. Si alguien lo sabe, por favor comparta sus ideas. Buscar en Google al iniciar procesos en segundo plano en Python aún no arroja luz.


Noté un posible "capricho" con el desarrollo de aplicaciones py2exe en pydev + eclipse. pude decir que el script principal no estaba separado porque la ventana de salida de eclipse no estaba terminando; incluso si el script se ejecuta hasta su finalización, todavía está esperando devoluciones. pero, cuando intenté compilar en un ejecutable py2exe, ocurre el comportamiento esperado (ejecuta los procesos como separados, luego se cierra). No estoy seguro, pero el nombre del ejecutable ya no está en la lista de procesos. esto funciona para todos los enfoques (os.system ("start *"), os.spawnl con os.P_DETACH, subprocs, etc.)
maranas

1
También es posible que necesites el indicador CREATE_NEW_PROCESS_GROUP. Vea a Popen esperando el proceso hijo incluso cuando el hijo inmediato ha finalizado
jfs

55
Lo siguiente es incorrecto: "[o] n windows (win xp), el proceso padre no finalizará hasta que longtask.py haya terminado su trabajo". El padre saldrá normalmente, pero la ventana de la consola (instancia de conhost.exe) solo se cierra cuando sale el último proceso adjunto, y el hijo puede haber heredado la consola del padre. Configuración DETACHED_PROCESSde creationflagsevita esto evitando que el niño herede o la creación de una consola. Si, en cambio, desea una nueva consola, use CREATE_NEW_CONSOLE(0x00000010).
Eryk dom

1
No quise decir que ejecutar como un proceso separado es incorrecto. Dicho esto, es posible que deba configurar los identificadores estándar para archivos, canalizaciones o os.devnullporque, de lo contrario , algunos programas de consola salen con un error. Cree una nueva consola cuando desee que el proceso secundario interactúe con el usuario simultáneamente con el proceso primario. Sería confuso intentar hacer ambas cosas en una sola ventana.
Eryk dom

1
¿No hay una manera independiente del sistema operativo para ejecutar el proceso en segundo plano?
Charlie Parker

152
import os
os.system("your command")

Tenga en cuenta que esto es peligroso, ya que el comando no se limpia. Te dejo a Google la documentación relevante sobre los módulos 'os' y 'sys'. Hay un montón de funciones (exec * y spawn *) que harán cosas similares.


66
No tengo idea de lo que quise decir hace casi una década (¡compruebe la fecha!), Pero si tuviera que adivinar, sería que no se realiza ninguna validación.
nimish

1
Esto debería señalar ahora subprocesscomo una solución ligeramente más versátil y portátil. Por supuesto, ejecutar comandos externos es inherentemente inportable (debe asegurarse de que el comando esté disponible en todas las arquitecturas que necesita admitir) y pasar la entrada del usuario como un comando externo es inherentemente inseguro.
tripleee

1
Tenga en cuenta la marca de tiempo en este tipo: la respuesta "correcta" tiene 40 veces los votos y es la respuesta # 1.
nimish

La única solución que funcionó para mí para ejecutar cosas de NodeJS.
Nikolay Shindarov

148

Recomiendo utilizar el módulo de subproceso en lugar de os.system porque escapa de shell por usted y, por lo tanto, es mucho más seguro.

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

Si desea crear una lista a partir de un comando con parámetros , una lista que se puede usar con subprocesscuándo shell=False, luego use shlex.splituna manera fácil de hacerlo docs.python.org/2/library/shlex.html#shlex.split ( es la forma recomendada de acuerdo con los documentos docs.python.org/2/library/subprocess.html#popen-constructor )
Daniel F

66
Esto es incorrecto: " se escapa por usted y, por lo tanto, es mucho más seguro ". el subproceso no escapa del shell, el subproceso no pasa su comando a través del shell, por lo que no hay necesidad de escapar del shell.
Lie Ryan

144
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 del módulo de subproceso , que otras respuestas han cubierto bien.


10
popen está en desuso a favor del subproceso .
Fox Wilson

También puede guardar su resultado con la llamada os.system, ya que funciona como el shell de UNIX, como por ejemplo os.system ('ls -l> test2.txt')
Stefan Gruenwald

97

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

Fuentes:

Estas son todas las bibliotecas:

Esperemos 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 canales 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 a comandos externos con os.systemy os.popen(Nota: También hay un subproceso.popen). os siempre ejecutará el shell y es una alternativa simple para las personas que no lo necesitan o que no saben cómo usarlo 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 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 le permite generar aplicaciones secundarias, controlarlas y encontrar patrones en su salida. Esta es una mejor alternativa al subproceso para los comandos que esperan un tty en Unix.

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

tela

fabric es una biblioteca de 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

enviado se conoce como "subproceso para los humanos". Se utiliza como una envoltura conveniente alrededor del subprocessmódulo.

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

comandos

commandscontiene funciones de contenedor para os.popen, pero se ha eliminado de Python 3 ya que subprocesses una mejor alternativa.

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


74

Siempre uso fabricpara 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 de subproceso de Python) .

Mira un ejemplo:

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

73

Compruebe también la biblioteca Python "pexpect".

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

child = pexpect.spawn('ftp 192.168.0.24')

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

child.sendline('anonymous')

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

70

Con la biblioteca estándar

Use el módulo de subproceso (Python 3):

import subprocess
subprocess.run(['ls', '-l'])

Es la forma estándar recomendada. Sin embargo, las tareas más complicadas (canalizaciones, salida, entrada, etc.) pueden ser tediosas de construir y escribir.

Nota sobre la versión de Python: si todavía usa Python 2, subprocess.call funciona de manera similar.

ProTip: shlex.split puede ayudarlo a analizar el comando para run, cally otras subprocessfunciones en caso de que no quiera (o no pueda) proporcionarlas en forma de listas:

import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))

Con dependencias externas

Si no le importan las dependencias externas, use plumbum :

from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())

Es el mejor subprocessenvoltorio. Es multiplataforma, es decir, funciona tanto en sistemas Windows como Unix. Instalar por pip install plumbum.

Otra biblioteca popular es sh :

from sh import ifconfig
print(ifconfig('wlan0'))

Sin embargo, shdejó de admitir Windows, por lo que ya no es tan impresionante como solía ser. Instalar por pip install sh.


69

Si necesita la salida del comando que está llamando, puede usar subprocess.check_output (Python 2.7+).

>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18  2007 /dev/null\n'

También tenga en cuenta el parámetro de shell .

Si el shell es True, el comando especificado se ejecutará a través del shell. Esto puede ser útil si está utilizando Python principalmente para el flujo de control mejorado que ofrece sobre la mayoría de los shells del sistema y aún desea un acceso conveniente a otras características de shell, como tuberías de shell, comodines de nombre de archivo, expansión de variable de entorno y expansión de ~ a la página de inicio de un usuario directorio. Sin embargo, nota que el propio Python ofrece implementaciones de muchos de concha características (en particular, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), y shutil).


1
Tenga en cuenta que check_outputrequiere una lista en lugar de una cadena. Si no confía en los espacios entre comillas para que su llamada sea válida, la forma más simple y fácil de hacerlo es subprocess.check_output("ls -l /dev/null".split()).
Bruno Bronosky

56

Así es como ejecuto mis comandos. Este código tiene todo lo que necesitas prácticamente

from subprocess import Popen, PIPE
cmd = "ls -l ~/"
p = Popen(cmd , shell=True, stdout=PIPE, stderr=PIPE)
out, err = p.communicate()
print "Return code: ", p.returncode
print out.rstrip(), err.rstrip()

3
Creo que es aceptable para los comandos codificados, si aumenta la legibilidad.
Adam Matan

54

Actualizar:

subprocess.runes el enfoque recomendado a partir de Python 3.5 si su código no necesita mantener la compatibilidad con versiones anteriores de Python. Es más consistente y ofrece una facilidad de uso similar a Envoy. (Sin embargo, las tuberías no son tan sencillas. Consulte esta pregunta para saber cómo ).

Aquí hay algunos ejemplos de la documentación .

Ejecute un proceso:

>>> subprocess.run(["ls", "-l"])  # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)

Elevar en ejecución fallida:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Salida de captura:

>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')

Respuesta original:

Recomiendo probar Envoy . Es un contenedor para subprocesos, que a su vez tiene como objetivo reemplazar los módulos y funciones más antiguos. El enviado es un subproceso para los humanos.

Ejemplo de uso de README :

>>> r = envoy.run('git config', data='data to pipe in', timeout=2)

>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''

Tubería cosas alrededor también:

>>> r = envoy.run('uptime | pbcopy')

>>> r.command
'pbcopy'
>>> r.status_code
0

>>> r.history
[<Response 'uptime'>]


36

os.systemestá bien, pero un poco anticuado. Tampoco es muy seguro. En cambio, inténtalo subprocess. subprocessno llama a sh directamente y, por lo tanto, es más seguro que os.system.

Obtenga más información aquí .


2
Si bien estoy de acuerdo con la recomendación general, subprocessno elimina todos los problemas de seguridad y tiene algunos problemas molestos.
tripleee

36

Llamar a un comando externo en Python

Simple, use subprocess.run, que devuelve un CompletedProcessobjeto:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

¿Por qué?

A partir de Python 3.5, la documentación recomienda subprocess.run :

El enfoque recomendado para invocar subprocesos es utilizar la función run () para todos los casos de uso que pueda manejar. Para casos de uso más avanzados, la interfaz de Popen subyacente se puede usar directamente.

Aquí hay un ejemplo del uso más simple posible, y hace exactamente lo que se le pide:

>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)

runespera a que el comando finalice correctamente y luego devuelve un CompletedProcessobjeto. En su lugar, puede aumentar TimeoutExpired(si le da un timeout=argumento) o CalledProcessError(si falla y pasa check=True).

Como puede deducir del ejemplo anterior, stdout y stderr se canalizan a su propio stdout y stderr de forma predeterminada.

Podemos inspeccionar el objeto devuelto y ver el comando que se le dio y el código de retorno:

>>> completed_process.args
'python --version'
>>> completed_process.returncode
0

Captura de salida

Si desea capturar la salida, puede pasar subprocess.PIPEa la correspondiente stderro stdout:

>>> cp = subprocess.run('python --version', 
                        stderr=subprocess.PIPE, 
                        stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''

(Me parece interesante y ligeramente contradictorio que la información de la versión se ponga en stderr en lugar de stdout).

Pase una lista de comandos

Uno podría pasar fácilmente de proporcionar manualmente una cadena de comando (como sugiere la pregunta) a proporcionar una cadena construida programáticamente. No construya cadenas mediante programación. Este es un posible problema de seguridad. Es mejor asumir que no confía en la entrada.

>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n  This is indented.\r\n'

Nota solo args debe pasarse posicionalmente.

Firma completa

Aquí está la firma real en la fuente y como lo muestra help(run):

def run(*popenargs, input=None, timeout=None, check=False, **kwargs):

Los popenargsy kwargsson dados al Popenconstructor. inputpuede ser una cadena de bytes (o unicode, si especifica la codificación ouniversal_newlines=True ) que se canalizarán al stdin del subproceso.

La documentación describe timeout=y check=Truemejor de lo que podría:

El argumento de tiempo de espera se pasa a Popen.communicate (). Si el tiempo de espera expira, el proceso secundario se cancelará y se esperará. La excepción TimeoutExpired se volverá a generar después de que el proceso secundario haya finalizado.

Si la comprobación es verdadera y el proceso sale con un código de salida distinto de cero, se generará una excepción CalledProcessError. Los atributos de esa excepción contienen los argumentos, el código de salida y stdout y stderr si fueron capturados.

y este ejemplo check=Truees mejor que uno que se me ocurra:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

Firma ampliada

Aquí hay una firma expandida, como se indica en la documentación:

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, 
shell=False, cwd=None, timeout=None, check=False, encoding=None, 
errors=None)

Tenga en cuenta que esto indica que solo la lista de argumentos debe pasarse posicionalmente. Entonces pase los argumentos restantes como argumentos de palabras clave.

Popen

Cuando uso Popenen su lugar? Me gustaría encontrar un caso de uso basado solo en los argumentos. PopenSin embargo, el uso directo de daría acceso a sus métodos, incluidospoll 'send_signal', 'terminar' y 'esperar'.

Aquí está la Popenfirma que figura en la fuente . Creo que esta es la encapsulación más precisa de la información (a diferencia de help(Popen)):

def __init__(self, args, bufsize=-1, executable=None,
             stdin=None, stdout=None, stderr=None,
             preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
             shell=False, cwd=None, env=None, universal_newlines=False,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, encoding=None, errors=None):

Pero más informativa es la Popendocumentación :

subprocess.Popen(args, bufsize=-1, executable=None, stdin=None,
                 stdout=None, stderr=None, preexec_fn=None, close_fds=True,
                 shell=False, cwd=None, env=None, universal_newlines=False,
                 startupinfo=None, creationflags=0, restore_signals=True,
                 start_new_session=False, pass_fds=(), *, encoding=None, errors=None)

Ejecute un programa hijo en un nuevo proceso. En POSIX, la clase usa un comportamiento similar a os.execvp () para ejecutar el programa secundario. En Windows, la clase usa la función Windows CreateProcess (). Los argumentos para Popen son los siguientes.

Comprender la documentación restante Popense dejará como un ejercicio para el lector.


Puede encontrar un ejemplo simple de comunicación bidireccional entre un proceso primario y un subproceso aquí: stackoverflow.com/a/52841475/1349673
James Hirschorn

El primer ejemplo probablemente debería tener shell=Trueo (mejor aún) pasar el comando como una lista.
tripleee

33

También hay Plumbum

>>> from plumbum import local
>>> ls = local["ls"]
>>> ls
LocalCommand(<LocalPath /bin/ls>)
>>> ls()
u'build.py\ndist\ndocs\nLICENSE\nplumbum\nREADME.rst\nsetup.py\ntests\ntodo.txt\n'
>>> notepad = local["c:\\windows\\notepad.exe"]
>>> notepad()                                   # Notepad window pops up
u''                                             # Notepad window is closed by user, command returns

28

Utilizar:

import os

cmd = 'ls -al'

os.system(cmd)

os: este módulo proporciona una forma portátil de utilizar la funcionalidad dependiente del sistema operativo.

Para más osfunciones, aquí está la documentación.


2
También está en desuso. usar subproceso
Corey Goldberg

28

Puede ser así de simple:

import os
cmd = "your command"
os.system(cmd)

1
Esto no señala los inconvenientes, que se explican con mucho más detalle en PEP-324 . La documentación para os.systemexplícitamente recomienda evitarlo a favor de subprocess.
tripleee

25

Me gusta bastante shell_command por su simplicidad. Está construido sobre el módulo de subproceso.

Aquí hay un ejemplo de la documentación:

>>> from shell_command import shell_call
>>> shell_call("ls *.py")
setup.py  shell_command.py  test_shell_command.py
0
>>> shell_call("ls -l *.py")
-rw-r--r-- 1 ncoghlan ncoghlan  391 2011-12-11 12:07 setup.py
-rw-r--r-- 1 ncoghlan ncoghlan 7855 2011-12-11 16:16 shell_command.py
-rwxr-xr-x 1 ncoghlan ncoghlan 8463 2011-12-11 16:17 test_shell_command.py
0

24

Hay otra diferencia aquí que no se menciona anteriormente.

subprocess.Popenejecuta el <comando> como un subproceso. En mi caso, necesito ejecutar el archivo <a> que necesita comunicarse con otro programa, <b>.

Intenté el subproceso y la ejecución fue exitosa. Sin embargo, <b> no pudo comunicarse con <a>. Todo es normal cuando ejecuto ambos desde la terminal.

Uno más: (NOTA: kwrite se comporta de manera diferente a otras aplicaciones. Si intenta lo siguiente con Firefox, los resultados no serán los mismos).

Si lo intenta os.system("kwrite"), el flujo del programa se congela hasta que el usuario cierre kwrite. Para superar eso intenté en su lugar os.system(konsole -e kwrite). Este programa de tiempo continuó fluyendo, pero kwrite se convirtió en el subproceso de la consola.

Cualquiera ejecuta kwrite sin ser un subproceso (es decir, en el monitor del sistema debe aparecer en el extremo izquierdo del árbol).


1
¿Qué quiere decir con "Alguien ejecuta el kwrite no siendo un subproceso" ?
Peter Mortensen

23

os.systemno le permite almacenar resultados, por lo que si desea almacenar los resultados en alguna lista o algo, subprocess.callfunciona.


22

subprocess.check_callEs conveniente si no desea probar los valores de retorno. Lanza una excepción en cualquier error.


22

Tiendo a usar el subproceso junto con shlex (para manejar el escape de cadenas entre comillas):

>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)

17

Plug descarado, escribí una biblioteca para esto: P https://github.com/houqp/shell.py

Es básicamente un envoltorio para popen y shlex por ahora. También admite comandos de canalización para que pueda encadenar comandos más fácilmente en Python. Entonces puedes hacer cosas como:

ex('echo hello shell.py') | "awk '{print $2}'"

16

En Windows, puede importar el subprocessmódulo y ejecutar comandos externos llamando subprocess.Popen(), subprocess.Popen().communicate()y de la subprocess.Popen().wait()siguiente manera:

# Python script to run a command line
import subprocess

def execute(cmd):
    """
        Purpose  : To execute a command and return exit status
        Argument : cmd - command to execute
        Return   : exit_code
    """
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    rc = process.wait()

    if rc != 0:
        print "Error: failed to execute command:", cmd
        print error
    return result
# def

command = "tasklist | grep python"
print "This process detail: \n", execute(command)

Salida:

This process detail:
python.exe                     604 RDP-Tcp#0                  4      5,660 K

15

En Linux, en caso de que desee llamar a un comando externo que se ejecutará de forma independiente (seguirá ejecutándose después de que finalice el script de Python), puede usar una cola simple como cola de tareas o el comando at

Un ejemplo con la cola de tareas:

import os
os.system('ts <your-command>')

Notas sobre la cola de tareas ( ts):

  1. Puede establecer el número de procesos concurrentes que se ejecutarán ("ranuras") con:

    ts -S <number-of-slots>

  2. La instalación tsno requiere privilegios de administrador. Puede descargarlo y compilarlo desde la fuente con un simple make, agregarlo a su ruta y listo.


1
tsno es estándar en ninguna distribución que conozco, aunque el puntero a ates ligeramente útil. Probablemente también deberías mencionarlo batch. Como en otros lugares, la os.system()recomendación probablemente debería mencionar al menos que subprocesses su reemplazo recomendado.
tripleee

15

Puede usar Popen, y luego puede verificar el estado del procedimiento:

from subprocess import Popen

proc = Popen(['ls', '-l'])
if proc.poll() is None:
    proc.kill()

Echa un vistazo al subproceso . Abrir .


15

Para obtener la identificación de red de OpenStack Neutron :

#!/usr/bin/python
import os
netid = "nova net-list | awk '/ External / { print $2 }'"
temp = os.popen(netid).read()  /* Here temp also contains new line (\n) */
networkId = temp.rstrip()
print(networkId)

Salida de nova net-list

+--------------------------------------+------------+------+
| ID                                   | Label      | CIDR |
+--------------------------------------+------------+------+
| 431c9014-5b5d-4b51-a357-66020ffbb123 | test1      | None |
| 27a74fcd-37c0-4789-9414-9531b7e3f126 | External   | None |
| 5a2712e9-70dc-4b0e-9281-17e02f4684c9 | management | None |
| 7aa697f5-0e60-4c15-b4cc-9cb659698512 | Internal   | None |
+--------------------------------------+------------+------+

Salida de impresión (networkId)

27a74fcd-37c0-4789-9414-9531b7e3f126

No debería recomendar os.popen()en 2016. El script Awk podría reemplazarse fácilmente con el código nativo de Python.
tripleee
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.