Llamar a un comando externo desde Python

Llamar a un comando externo desde Python

¿Cómo se llama a 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?

Mostrar la mejor respuesta

Antes de publicar una nueva respuesta, considere que ya hay más de 60 respuestas para esta pregunta. Por favor, asegúrese de que su respuesta contribuya con información que no se encuentre entre las respuestas existentes.

Antes de usar el subproceso u os.system, considere buscar un paquete de Python que haga lo mismo. Por lo general, hay envoltorios sobre utilidades bash comúnmente utilizadas que puede aprovechar.

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.

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.

Ahora debería apuntar a subprocess como 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.

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

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

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.

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

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

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

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

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

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

El Reemplazar funciones más antiguas con La sección del módulo de subproceso en la documentación de subprocess 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 Intenté hacer echo $PATH usando call(["echo", "$PATH"]) , pero solo hizo eco de la cadena literal $PATH en lugar 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.

@KevinWheeler Tendrás que usar shell=True para que eso funcione.

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

El ejemplo llama a ls -l pero no da acceso a su salida (stdout no es accesible). Me parece confuso: en su lugar, podría usar un comando sin stdout, como touch .

Parece ser bastante torpe en Python3 + Windows . Si ingreso un nombre de archivo con caracteres especiales como & , arrojará un FileNotFoundError . Aunque el archivo está en el directorio de trabajo donde ejecuté python, y obviamente existe.

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

Entiendo el uso de call para funciones más avanzadas, pero no veo nada de malo en usar system si hace lo que necesita.

Para simplificar al menos conceptualmente: \ n call ("ls -l" .split ())

Si desea crear una lista a partir de un comando con parámetros , una lista que puede usarse con subprocess cuando shell=False , luego use shlex.split para una manera fácil de hacer esto docs.python.org/ 2 / library / shlex.html # shlex.split

subprocess también le permite conectar directamente dos comandos, hay un ejemplo en los documentos.

@CharlieParker: call , check_call , check_output y run bloques. Si desea no bloquear, use subprocess.Popen .

@sudo: lo tienes al revés. system() es más avanzado que Popen , agrega un maldito shell que está listo para fastidiarte cuando menos lo esperas. Cual caparazón? Depende de lo que el usuario tenga como SHELL env, lo que significa que la sintaxis exacta que te atornillará a menudo está fuera de tu control. Popen es de nivel inferior y está más cerca de cómo se ve la API del sistema operativo subyacente, y tiene un comportamiento mucho menos sorprendente.

@LieRyan Usaría Popen si la sintaxis exacta fuera algo de lo que preocuparse, pero si solo está ejecutando algún programa (tal vez con un par de argumentos constantes), system no un problema. Además, a veces quiero el caparazón.

olvidó decir que necesita Python 3.5 al menos. No funciona en Python 3.4.3, por ejemplo, que es el predeterminado para Ubuntu 14.04 LTS

Como ya se mencionó, esto solo se admite en versiones recientes de python. Creo que esto debería indicarse en la respuesta

La respuesta original tenía subprocess.call() , por lo que la persona que actualizó la respuesta (¡no el respondedor original!) También debería explicar este cambio con más detalle.

También puede pasar como cadena en lugar de una lista de cadenas: subprocess.run("ls -l")

Si quieren nombrarlo run en lugar de call , ¿por qué no simplemente convertirlo en un alias? Algunos tipos de compatibilidad con versiones anteriores son difíciles y permiten que continúen los patrones propensos a errores, pero hacer run == call es fácil, simple y casi sin costo. ¿Por qué call para versiones de Python anteriores a 3.5 en lugar de versiones nuevas y antiguas?

@SamuelMuldoon El problema es que subprocess.call tiene una semántica completamente diferente de subprocess.run . subprocess.call todavía existe en Python 3.5–3.8 (para compatibilidad con versiones anteriores), es solo que si lo tiene disponible, subprocess.run es mejor con diferencia.

Recomiendo usar 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: http://docs.python.org/library/subprocess.html

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

Si quiere crear una lista a partir de un comando con parámetros , una lista que se puede usar con subprocess cuando shell=False , luego use shlex.split para una manera fácil de hacer esto docs.python.org/ 2 / library / shlex.html # shlex.split (es la forma recomendada según los documentos docs.python.org/2/library/subprocess.html#popen-constructor )

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.

Utilice subproceso .

... o para un comando muy simple:

import os
os.system('cat testfile')
 

os.system está bien, pero está un poco anticuado. Tampoco es muy seguro. En su lugar, intente subprocess . subprocess no llama a sh directamente y, por lo tanto, es más seguro que os.system .

Obtenga más información aquí .

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

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, si bien 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. Consulte la documentación .

  1. 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 se pasa al shell; si los pasa como una lista, entonces no necesita preocuparse por escapar de nada. Consulte la documentación .

  2. La clase Popen del módulo subprocess . Esto pretende ser un reemplazo de os.popen pero tiene la desventaja de ser un poco más complicado en virtud de ser tan completo. Por ejemplo, diría:

    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 de popen diferentes. Consulte la documentación .

  3. La función call del módulo subprocess . Esto es básicamente como la clase Popen 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)  
     

    Consulte la documentación .

  4. Si está en Python 3.5 o posterior, puede usar el nuevo función subprocess.run , que es muy parecida a la anterior pero aún más flexible y devuelve una objeto CompletedProcess 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 módulo subprocess 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.

Lo que normalmente se necesita saber es qué se hace con STDOUT y STDERR del proceso hijo, porque si se ignoran, en algunas condiciones (bastante comunes), eventualmente el proceso hijo 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 actualmente recomendadas, subprocess.run(..) , ¿qué significa exactamente "Esto no captura stdout o stderr por defecto" ? ¿Qué pasa con subprocess.check_output(..) y STDERR?

¿Cuál de los comandos que recomendó bloquea mi script? es decir, si quiero ejecutar varios comandos en un bucle for , ¿cómo lo hago sin bloquear mi script de Python? No me importa la salida del comando, solo quiero ejecutar muchos de ellos.

@ Phoenix no estoy de acuerdo. No hay nada que le impida utilizar os.system en python3 docs.python. org / 3 / library / os.html # os.system

mi mamá no me amó && rm -rf / no hará nada: D Probablemente mi mamá no me amó || rm -rf / será más peligroso :)

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

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, consulte subprocess.Popen() . os.popen() quizás no debería mencionarse en absoluto, o incluso después de "piratear su propio código fork / exec / spawn".

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

Avatar jfs

.readlines() lee todas líneas a la vez, es decir, bloquea hasta que sale el subproceso (cierra su 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,

¿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?

Avatar jfs

el proceso secundario puede usar el almacenamiento en bloque en modo no interactivo en lugar del almacenamiento en línea para que p.stdout.readline() (nota: no s al final) no vea ningún dato hasta que el niño llena su búfer 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 ())? . Se proporcionan algunas soluciones en esta respuesta (pexpect, pty, stdbuf)

Avatar jfs

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 datos

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

¿Qué quiere decir con "Alguien ejecuta kwrite sin ser un subproceso" ?

Algunas sugerencias para separar el proceso hijo del que llama (iniciar 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 proceso 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 @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 el proceso hijo. 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 verificado el código en otras plataformas y no sé las razones del comportamiento en FreeBSD. Si alguien lo sabe, por favor comparta sus ideas. Buscar en Google al iniciar procesos en segundo plano en Python todavía no arroja ninguna 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 (sistema os. ("inicio *"), os.spawnl con os.P_DETACH, subprocs, etc.)

Problema de Windows: aunque generé el proceso con DETACHED_PROCESS, cuando eliminé mi demonio Python, todos los puertos abiertos por él no se liberarían hasta que finalicen todos los procesos generados. WScript.Shell resolvió todos mis problemas. Ejemplo aquí: pastebin.com/xGmuvwSx

Avatar jfs

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

Estoy viendo que import subprocess as sp;sp.Popen('calc') no está esperando que se complete el subproceso. Parece que las banderas de creación no son necesarias. ¿Qué me estoy perdiendo?

@ubershmekel, no estoy seguro de lo que quieres decir y no tengo una instalación de Windows. Si recuerdo correctamente, sin los indicadores no puede cerrar la instancia de cmd desde la que inició el calc .

Estoy en Windows 8.1 y calc parece sobrevivir al cierre de python .

¿Hay algún significado para usar '0x00000008'? ¿Es ese un valor específico que debe usarse o una de las múltiples opciones?

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. Establecer DETACHED_PROCESS en creationflags evita esto al evitar que el niño herede o cree una consola. Si en cambio desea una nueva consola, use CREATE_NEW_CONSOLE (0x00000010).

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.devnull porque, 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.

stdout=subprocess.PIPE hará que su código cuelgue si tiene una salida larga de un niño. Para obtener más detalles, consulte thraxil .org / users / anders / posts / 2008/03/13 / ...

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

tu respuesta me parece extraña Acabo de abrir un subprocess.Popen y no pasó nada malo (no tuve que esperar). ¿Por qué exactamente debemos preocuparnos por el escenario que está señalando? Soy escéptico

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

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

Si necesita la salida del comando que está llamando, entonces 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 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, tenga en cuenta que Python ofrece implementaciones de muchas características similares a las de shell (en particular, glob , fnmatch , os.walk() , os.path.expandvars() , os.path.expanduser() y shutil ).

Tenga en cuenta que check_output requiere 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 legible de hacerlo es subprocess.check_output("ls -l /dev/null".split()) .

Siempre uso fabric para estas 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)
 

os.system no le permite almacenar resultados, por lo que si desea almacenar los resultados en alguna lista o algo, un subprocess.call funciona.

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

Consulte subprocess.Popen .

La forma más sencilla de ejecutar cualquier comando y recuperar el resultado:

from commands import getstatusoutput

try:
    return getstatusoutput("ls -ltr")
except Exception, e:
    return None
 

¿Esto va a estar en desuso en python 3.0?

De hecho, la commands documentación de Python 2.7 lo dice quedó en desuso en 2.6 y se eliminará en 3.0.

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
 

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

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

Avatar Joe

Actualización:

subprocess.run es 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 sobre 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)
 

Aumento 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 más antiguos y funciones Enviado es un subproceso para los humanos.

Ejemplo de uso de the 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 alrededor también:

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

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

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

Con la biblioteca estándar

Utilice 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 , call y otras funciones subprocess en caso de que no desee (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 contenedor subprocess . Es multiplataforma, es decir, funciona en sistemas Windows y Unix. Instalar por pip install plumbum .

Otra biblioteca popular es sh :

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

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

Hay muchas formas diferentes de ejecutar comandos externos en Python, y todos ellos tienen sus propias ventajas e inconvenientes.

Mis colegas y yo hemos estado escribiendo herramientas de administración del sistema Python, por lo que necesitamos ejecutar muchos comandos externos y, a veces, desea que bloqueen o se ejecuten de forma asincrónica, tiempo de espera, actualización cada segundo, etc.

También hay diferentes formas de manejar el código de retorno y los errores, y es posible que desee analizar la salida y proporcionar una nueva entrada (en un esperar tipo de estilo ) O deberá redirigir stdin, stdout y stderr para que se ejecuten en un tty diferente (por ejemplo, cuando se usa la pantalla).

Entonces probablemente tendrá que escribir muchos contenedores alrededor del comando externo. Así que aquí hay un módulo de Python que hemos escrito que puede manejar casi cualquier cosa que desee, y si no, es muy flexible para que pueda extenderlo fácilmente:

https://github.com /hpcugent/vsc-base/blob/master/lib/vsc/utils/run.py

actualización: no funciona de manera independiente y requiere algunas de nuestras otras herramientas, y obtuvo una gran cantidad de funcionalidades especializadas a lo largo de los años, por lo que puede que no sea una caída de reemplazo para usted, pero puede brindarle mucha información sobre cómo funcionan las partes internas de Python para ejecutar comandos y las ideas sobre cómo manejar ciertas situaciones.

Sin la salida del resultado:

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

Con salida del resultado:

import commands
commands.getoutput("your command here")
or
commands.getstatusoutput("your command here")
 

commands ya no está disponible en Python 3. Debería preferir subprocess sobre os.system()

El módulo de subproceso descrito anteriormente por Eli es muy poderoso, pero la sintaxis hacer una llamada de sistema estándar de pantano e inspeccionar su salida es innecesariamente prolijo.

La forma más fácil de hacer una llamada al sistema es con el módulo de comandos ( Solo Linux).

> import commands
> commands.getstatusoutput("grep matter alice-in-wonderland.txt")
(0, "'Then it doesn't matter which way you go,' said the Cat.")
 

El primer elemento de la tupla es el código de retorno del proceso. El segundo elemento es su salida estándar (y error estándar, combinado).


Los desarrolladores de Python han "desaprobado" el módulo de comandos, pero eso no significa que no debas usarlo. Solo que ya no lo están desarrollando, lo cual está bien, porque ya es perfecto (en su función pequeña pero importante).

En desuso no solo significa "ya no se desarrolla", sino también "no se recomienda usar esto". Las funciones obsoletas pueden romperse en cualquier momento, pueden eliminarse en cualquier momento o pueden ser peligrosas. Nunca debe usar esto en un código importante. La desaprobación es simplemente una mejor manera de eliminar una característica de inmediato, ya que les da a los programadores el tiempo para adaptar y reemplazar sus funciones desaprobadas.

Solo para probar mi punto: "Desaprobado desde la versión 2.6: el módulo de comandos se ha eliminado en Python 3. Utilice el módulo de subproceso en su lugar".

¡No es peligroso! Los desarrolladores de Python son cuidadosos solo para romper las características entre las versiones principales (es decir, entre 2.xy 3.x). He estado usando el módulo de comandos desde Python 2.4 de 2004. Funciona igual hoy en Python 2.7.

Con peligroso, no quise decir que se puede eliminar en cualquier momento (ese es un problema diferente), tampoco dije que es peligroso usar este módulo específico. Sin embargo, puede volverse peligroso si se descubre una vulnerabilidad de seguridad pero el módulo no se desarrolla ni se mantiene más. (No quiero decir que este módulo es o no vulnerable a problemas de seguridad, solo hablando de cosas obsoletas en general)

Solo para agregar a la discusión, si incluye el uso de una consola Python, puede llamar a comandos externos desde IPython . Mientras está en el indicador de IPython, puede llamar a los comandos de shell con el prefijo '!'. También puede combinar el código Python con el shell y asignar la salida de los scripts del shell a las variables de Python.

Por ejemplo:

In [9]: mylist = !ls

In [10]: mylist
Out[10]:
['file1',
 'file2',
 'file3',]
 

Después de investigar un poco, tengo el siguiente código que me funciona muy bien. Básicamente imprime stdout y stderr en tiempo real.

stdout_result = 1
stderr_result = 1


def stdout_thread(pipe):
    global stdout_result
    while True:
        out = pipe.stdout.read(1)
        stdout_result = pipe.poll()
        if out == '' and stdout_result is not None:
            break

        if out != '':
            sys.stdout.write(out)
            sys.stdout.flush()


def stderr_thread(pipe):
    global stderr_result
    while True:
        err = pipe.stderr.read(1)
        stderr_result = pipe.poll()
        if err == '' and stderr_result is not None:
            break

        if err != '':
            sys.stdout.write(err)
            sys.stdout.flush()


def exec_command(command, cwd=None):
    if cwd is not None:
        print '[' + ' '.join(command) + '] in ' + cwd
    else:
        print '[' + ' '.join(command) + ']'

    p = subprocess.Popen(
        command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
    )

    out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
    err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))

    err_thread.start()
    out_thread.start()

    out_thread.join()
    err_thread.join()

    return stdout_result + stderr_result
 

Avatar jfs

su código puede perder datos cuando se cierra el subproceso mientras hay algunos datos almacenados en el búfer. Lea hasta EOF, consulte teed_call ()

Utilice subprocess.call :

 from subprocess import call

# Using list
call(["echo", "Hello", "world"])

# Single string argument varies across platforms so better split it
call("echo Hello world".split(" "))
  

Tiendo a utilizar 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)
 

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

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

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

Una forma sencilla es utilizar el módulo os :

import os
os.system('ls')
 

Alternativamente, también puede usar el módulo de subproceso:

import subprocess
subprocess.check_call('ls')
 

Si desea que el resultado se almacene en una variable, pruebe:

import subprocess
r = subprocess.check_output('ls')
 

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
 

Uso:

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 las funciones más os , aquí está la documentación.

También está en desuso. usar subproceso

Usar la función Popen del módulo Python subprocess es la forma más sencilla de ejecutar comandos de Linux. En eso, la función Popen.communicate() le dará salida a sus comandos. Por ejemplo

import subprocess

..
process = subprocess.Popen(..)   # Pass command and arguments to the function
stdout, stderr = process.communicate()   # Get command output and error
..
 

Esto ya no es cierto, y probablemente no lo fue cuando se publicó esta respuesta. Debes preferir subprocess.check_call() y amigos a menos que necesites absolutamente el control de nivel inferior del Popen() más complejo. En versiones recientes de Python, el caballo de batalla es subprocess.run()

Aquí están mis dos centavos: en mi opinión, esta es la mejor práctica cuando se trata de comandos externos ...

Estos son los valores de retorno del método de ejecución ...

pass, stdout, stderr = execute(["ls","-la"],"/home/user/desktop")
 

Este es el método de ejecución ...

def execute(cmdArray,workingDir):

    stdout = ''
    stderr = ''

    try:
        try:
            process = subprocess.Popen(cmdArray,cwd=workingDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1)
        except OSError:
            return [False, '', 'ERROR : command(' + ' '.join(cmdArray) + ') could not get executed!']

        for line in iter(process.stdout.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stdout += echoLine

        for line in iter(process.stderr.readline, b''):

            try:
                echoLine = line.decode("utf-8")
            except:
                echoLine = str(line)

            stderr += echoLine

    except (KeyboardInterrupt,SystemExit) as err:
        return [False,'',str(err)]

    process.stdout.close()

    returnCode = process.wait()
    if returnCode != 0 or stderr != '':
        return [False, stdout, stderr]
    else:
        return [True, stdout, stderr]
 

Potencial de punto muerto: utilice el método .communicate en su lugar

Mejor aún, evite Popen() y use la API de nivel superior que ahora se recopila en la función única subprocess.run()

Para Python 3.5+ se recomienda que utilice la función de ejecución run desde el módulo de subproceso . Esto devuelve un objeto CompletedProcess , desde el cual puede obtener fácilmente la salida y el código de retorno.

from subprocess import PIPE, run

command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)
 

La respuesta con la función de ejecución se agregó en 2015 años. Lo has repetido. Creo que fue un motivo de voto negativo

Recomendaría el siguiente método 'run' y nos ayudará a obtener STDOUT, STDERR y salir del estado como diccionario; La persona que llama puede leer el retorno del diccionario mediante el método 'ejecutar' para conocer el estado real del proceso.

  def run (cmd):
       print "+ DEBUG exec({0})".format(cmd)
       p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
       (out, err) = p.communicate()
       ret        = p.wait()
       out        = filter(None, out.split('\n'))
       err        = filter(None, err.split('\n'))
       ret        = True if ret == 0 else False
       return dict({'output': out, 'error': err, 'status': ret})
  #end
 

Esto reimplementa de manera incompleta algo como subprocess.run() . En particular, debe evitar shell=True cuando no sea estrictamente necesario.

En Windows puede importar el módulo subprocess y ejecutar comandos externos llamando a subprocess.Popen() , subprocess.Popen().communicate() y subprocess.Popen().wait() de la 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
 

Uso:

import subprocess

p = subprocess.Popen("df -h", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")
 

Da una salida agradable con la que es más fácil trabajar:

['Filesystem      Size  Used Avail Use% Mounted on',
 '/dev/sda6        32G   21G   11G  67% /',
 'none            4.0K     0  4.0K   0% /sys/fs/cgroup',
 'udev            1.9G  4.0K  1.9G   1% /dev',
 'tmpfs           387M  1.4M  386M   1% /run',
 'none            5.0M     0  5.0M   0% /run/lock',
 'none            1.9G   58M  1.9G   3% /run/shm',
 'none            100M   32K  100M   1% /run/user',
 '/dev/sda5       340G  222G  100G  69% /home',
 '']
 

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

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

No debe recomendar os.popen() en 2016. El script Awk podría reemplazarse fácilmente con código nativo de Python.

Hay muchas formas de llamar a un comando.

  • Por ejemplo:

si and.exe necesita dos parámetros. En cmd podemos llamar a sample.exe use esto: and.exe 2 3 y muestra 5 en la pantalla.

Si usamos un script de Python para llamar a and.exe , deberíamos hacer como ...

  1. os.system(cmd,...)

    • os.system(("and.exe" + " " + "2" + " " + "3"))
  2. os.popen(cmd,...)

    • os.popen(("and.exe" + " " + "2" + " " + "3"))
  3. subprocess.Popen(cmd,...)
    • subprocess.Popen(("and.exe" + " " + "2" + " " + "3"))

Es demasiado difícil, por lo que podemos unir cmd con un espacio:

import os
cmd = " ".join(exename,parameters)
os.popen(cmd)
 

os.popen no debe recomendarse y quizás incluso mencionarse más. El ejemplo subpocess debe pasar los argumentos como una lista en lugar de unirlos con espacios.

Aquí se llama a un comando externo y se devuelve o imprime la salida del comando:

Python Subproceso check_output es bueno para

Ejecute el comando con argumentos y devuelva su salida como una cadena de bytes.

import subprocess
proc = subprocess.check_output('ipconfig /all')
print proc
 

El argumento debe estar correctamente tokenizado en una lista, o debe pasar explícitamente en shell=True . En Python 3.x (donde creo que x> 3) puede recuperar la salida como una cadena adecuada con universal_newlines=True y probablemente desee cambiar a subproces.run()

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 en comando

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 ("slots") con:

    ts -S <number-of-slots>

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

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

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

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

He escrito un contenedor para manejar errores y redirigir la salida y otras cosas.

import shlex
import psutil
import subprocess

def call_cmd(cmd, stdout=sys.stdout, quiet=False, shell=False, raise_exceptions=True, use_shlex=True, timeout=None):
    """Exec command by command line like 'ln -ls "/var/log"'
    """
    if not quiet:
        print("Run %s", str(cmd))
    if use_shlex and isinstance(cmd, (str, unicode)):
        cmd = shlex.split(cmd)
    if timeout is None:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
        retcode = process.wait()
    else:
        process = subprocess.Popen(cmd, stdout=stdout, stderr=sys.stderr, shell=shell)
        p = psutil.Process(process.pid)
        finish, alive = psutil.wait_procs([p], timeout)
        if len(alive) > 0:
            ps = p.children()
            ps.insert(0, p)
            print('waiting for timeout again due to child process check')
            finish, alive = psutil.wait_procs(ps, 0)
        if len(alive) > 0:
            print('process {} will be killed'.format([p.pid for p in alive]))
            for p in alive:
                p.kill()
            if raise_exceptions:
                print('External program timeout at {} {}'.format(timeout, cmd))
                raise CalledProcessTimeout(1, cmd)
        retcode = process.wait()
    if retcode and raise_exceptions:
        print("External program failed %s", str(cmd))
        raise subprocess.CalledProcessError(retcode, cmd)
 

Puedes llamarlo así:

cmd = 'ln -ls "/var/log"'
stdout = 'out.txt'
call_cmd(cmd, stdout)
 

Como ejemplo (en Linux):

import subprocess
subprocess.run('mkdir test.dir', shell=True)
 

Esto crea test.dir en el directorio actual. Tenga en cuenta que esto también funciona:

import subprocess
subprocess.call('mkdir test.dir', shell=True)
 

El código equivalente que usa os.system es:

import os
os.system('mkdir test.dir')
 

La mejor práctica sería utilizar subprocesos en lugar de os, con .run como favorito sobre .call. Todo lo que necesita saber sobre el subproceso es aquí . Además, tenga en cuenta que toda la documentación de Python se puede descargar de aquí . Descargué el PDF empaquetado como .zip. Menciono esto porque hay una buena descripción del módulo os en tutorial.pdf (página 81). Además, es un recurso autorizado para los codificadores de Python.

@Nick Predley: anotado, pero "shell = False" no realiza la función deseada. ¿Cuáles son específicamente las preocupaciones de seguridad y cuál es la alternativa? Avíseme lo antes posible: no deseo publicar nada que pueda causar problemas a cualquiera que vea esto.

La advertencia básica se encuentra en la documentación, pero esta pregunta lo explica con más detalle: stackoverflow.com/questions/3172470/…

Avatar am5

A menudo, uso la siguiente función para comandos externos, y esto es especialmente útil para procesos de larga ejecución . El siguiente método sigue la salida del proceso mientras se está ejecutando y devuelve la salida, genera una excepción si el proceso falla.

Sale si el proceso se realiza utilizando el método poll () en el proceso .

import subprocess,sys

def exec_long_running_proc(command, args):
    cmd = "{} {}".format(command, " ".join(str(arg) if ' ' not in arg else arg.replace(' ','\ ') for arg in args))
    print(cmd)
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

    # Poll process for new output until finished
    while True:
        nextline = process.stdout.readline().decode('UTF-8')
        if nextline == '' and process.poll() is not None:
            break
        sys.stdout.write(nextline)
        sys.stdout.flush()

    output = process.communicate()[0]
    exitCode = process.returncode

    if (exitCode == 0):
        return output
    else:
        raise Exception(command, exitCode, output)
 

Puede invocarlo así:

exec_long_running_proc(command = "hive", args=["-f", hql_path])
 

Avatar sbk

Obtendrás resultados inesperados al pasar un argumento con espacio. Usar repr(arg) en lugar de str(arg) podría ayudar por la mera coincidencia de que python y sh escape se cita de la misma manera

Avatar am5

@sbk repr(arg) realmente no ayudó, el código anterior también maneja los espacios. Ahora lo siguiente funciona exec_long_running_proc(command = "ls", args=["-l", "~/test file*"])

Llamar a un comando externo en Python

Una forma sencilla de llamar a un comando externo es usar os.system(...) . Y esta función devuelve el valor de salida del comando. Pero el inconveniente es que no obtendremos stdout y stderr.

ret = os.system('some_cmd.sh')
if ret != 0 :
    print 'some_cmd.sh execution returned failure'
 

Llamar a un comando externo en Python en segundo plano

subprocess.Popen proporciona más flexibilidad para ejecutar un comando externo en lugar de usar os.system . Podemos iniciar un comando en segundo plano y esperar a que termine. Y después de eso podemos obtener stdout y stderr.

proc = subprocess.Popen(["./some_cmd.sh"], stdout=subprocess.PIPE)
print 'waiting for ' + str(proc.pid)
proc.wait()
print 'some_cmd.sh execution finished'
(out, err) = proc.communicate()
print 'some_cmd.sh output : ' + out
 

Llamar a un comando externo de larga ejecución en Python en segundo plano y detenerse después de un tiempo

Incluso podemos comenzar un proceso de larga ejecución en segundo plano usando subprocess.Popen y matarlo después de algún tiempo una vez que se complete su tarea.

proc = subprocess.Popen(["./some_long_run_cmd.sh"], stdout=subprocess.PIPE)
# Do something else
# Now some_long_run_cmd.sh exeuction is no longer needed, so kill it
os.system('kill -15 ' + str(proc.pid))
print 'Output : ' proc.communicate()[0]
 

Puede ser así de simple:

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

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

Si necesita llamar a un comando de shell desde un cuaderno de Python (como Jupyter , Zeppelin, Databricks o Google Cloud Datalab) solo puede usar el prefijo ! .

Por ejemplo,

!ls -ilF
 

Utilice el módulo os :

import os
os.system("your command")
 

Por ejemplo,

import os
os.system("ifconfig")
 

Esto duplica una respuesta (un poco) más detallada del abril anterior, que sin embargo tampoco señala las advertencias.

Invoke es una herramienta de ejecución de tareas Python (2.7 y 3.4+) y biblioteca. Proporciona una API limpia y de alto nivel para ejecutar comandos de shell

>>> from invoke import run
>>> cmd = "pip install -r requirements.txt"
>>> result = run(cmd, hide=True, warn=True)
>>> print(result.ok)
True
>>> print(result.stdout.splitlines()[-1])
Successfully installed invocations-0.13.0 pep8-1.5.7 spec-1.3.1
 

Esta es una gran biblioteca. Estaba tratando de explicárselo a un compañero de trabajo el otro día y lo describí así: invoke es subprocess como requests es urllib3 .

Escribí una pequeña biblioteca para ayudar con este caso de uso:

https://pypi.org/project/citizenshell/

Se puede instalar usando

pip install citizenshell
 

Y luego se usa de la siguiente manera:

from citizenshell import sh
assert sh("echo Hello World") == "Hello World"
 

Puede separar stdout de stderr y extraer el código de salida de la siguiente manera:

result = sh(">&2 echo error && echo output && exit 13")
assert result.stdout() == ["output"]
assert result.stderr() == ["error"]
assert result.exit_code() == 13
 

Y lo bueno es que no tiene que esperar a que salga el shell subyacente antes de comenzar a procesar la salida:

for line in sh("for i in 1 2 3 4; do echo -n 'It is '; date +%H:%M:%S; sleep 1; done", wait=False)
    print ">>>", line + "!"
 

imprimirá las líneas a medida que estén disponibles gracias a wait = False

>>> It is 14:24:52!
>>> It is 14:24:53!
>>> It is 14:24:54!
>>> It is 14:24:55!
 

Se pueden encontrar más ejemplos en https://github.com/meuter/citizenshell

Como algunas de las respuestas estaban relacionadas con las versiones anteriores de Python o estaban usando el módulo os.system , publico esta respuesta para personas como yo que tienen la intención de usar subprocess en Python 3.5 +. Lo siguiente me ayudó en Linux:

import subprocess

# subprocess.run() returns a completed process object that can be inspected
c = subprocess.run(["ls", "-ltrh"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(c.stdout.decode('utf-8'))
 

Como se menciona en la documentación , PIPE Los valores son secuencias de bytes y, para mostrarlos correctamente, debe considerarse la decodificación. Para versiones posteriores de Python, text=True y encoding='utf-8' se agregan a kwargs de subprocess.run() .

La salida del código mencionado anteriormente es:

total 113M
-rwxr-xr-x  1 farzad farzad  307 Jan 15  2018 vpnscript
-rwxrwxr-x  1 farzad farzad  204 Jan 15  2018 ex
drwxrwxr-x  4 farzad farzad 4.0K Jan 22  2018 scripts
.... # Some other lines
 

Hay dos formas destacadas en las que uno puede ejecutar comandos de shell utilizando Python. Los dos ejemplos mencionados a continuación muestran cómo se puede obtener el nombre del directorio de trabajo actual (pwd ) usando Python. Puede usar cualquier otro comando de Unix en lugar de pwd .

1.> 1er método: se puede usar el os de Python, y system () funciona desde allí para ejecutar comandos de shell en Python.

import os
os.system('pwd')
 

Salida:

/Users/siddharth
 

1.> Segundo método: Otra forma es usar el módulo de subproceso y función call () .

import subprocess
subprocess.call('pwd')
 

Salida:

/Users/siddharth
 

Si no usa la entrada del usuario en los comandos, puede usar esto:

from os import getcwd
from subprocess import check_output
from shlex import quote

def sh(command):
    return check_output(quote(command), shell=True, cwd=getcwd(), universal_newlines=True).strip()
 

Y úsalo como

branch = sh('git rev-parse --abbrev-ref HEAD')
 

shell=True generará un shell, por lo que puede usar tubería y esas cosas sh('ps aux | grep python') . Esto es muy muy útil para ejecutar comandos codificados y procesar su salida. El universal_lines=True asegura que la salida se devuelva en una cadena en lugar de binaria.

cwd=getcwd() se asegurará de que el comando se ejecute con el mismo directorio de trabajo que el intérprete. Esto es útil para que los comandos de Git funcionen como el ejemplo de nombre de rama de Git anterior.

Algunas recetas

  • memoria libre en megabytes: sh('free -m').split('\n')[1].split()[1]
  • espacio libre en / en porcentaje sh('df -m /').split('\n')[1].split()[4][0:-1]
  • Carga de CPU sum(map(float, sh('ps -ef -o pcpu').split('\n')[1:])

Pero esto no es seguro para la entrada del usuario, de la documentación:

Consideraciones de seguridad

A diferencia de otras funciones de popen, esta implementación nunca llama implícitamente a un shell del sistema. Esto significa que todos los personajes, incluidos los metacaracteres de shell, se pueden pasar de forma segura al niño procesos. Si el shell se invoca explícitamente, a través de shell = True, es la responsabilidad de la aplicación de garantizar que todos los espacios en blanco y los metacaracteres se citan apropiadamente para evitar la inyección de shell vulnerabilidades.

Cuando se usa shell = True, la función shlex.quote () se puede usar para escapar adecuadamente los espacios en blanco y metacaracteres de shell en cadenas que se utilizarán para construir comandos de shell.

Incluso usando el shlex.quote() , es bueno mantenerse un poco paranoico cuando se usan entradas de usuario en comandos de shell. Una opción es usar un comando codificado para tomar algunos resultados genéricos y filtrar por entrada del usuario. De todos modos, el uso de shell=False se asegurará de que solo se ejecute el proceso exacto que desea ejecutar o obtendrá un error de No such file or directory .

También hay un impacto en el rendimiento de shell=True , de mis pruebas parece un 20% más lento que shell=False (el valor predeterminado).

In [50]: timeit("check_output('ls -l'.split(), universal_newlines=True)", number=1000, globals=globals())
Out[50]: 2.6801227919995654

In [51]: timeit("check_output('ls -l', universal_newlines=True, shell=True)", number=1000, globals=globals())
Out[51]: 3.243950183999914
 

Sultan es un paquete reciente para este propósito. Proporciona algunas ventajas sobre la administración de privilegios de usuario y la adición de mensajes de error útiles.

 from sultan.api import Sultan

with Sultan.load(sudo=True, hostname="myserver.com") as sultan:
  sultan.yum("install -y tree").run()
  

Re "Proporciona algunas sutilezas" : ¿Puedes dar más detalles?

También puede usar subprocess.getoutput() y subprocess.getstatusutput() , que son Funciones de invocación de shell heredado del módulo commands en desuso, es decir:

subprocess.getstatusoutput(cmd)

Retorno (exitcode , output ) de ejecutar cmd en un shell.


subprocess.getoutput(cmd)

Devuelve la salida (stdout y stderr ) de ejecutar cmd en un shell.

Si está escribiendo un script de shell Python y tiene IPython instalado en su sistema, puedes usar la magia de explosión para ejecutar un comando dentro de IPython:

!ls
filelist = !ls
 

@ PeterMortensen No creo que funcione en DOS, pero debería funcionar en Cygwin.

Python 3.5+

 import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())
  

Pruebe en línea

 import subprocess

p = subprocess.run(["ls", "-ltr"], capture_output=True)
print(p.stdout.decode(), p.stderr.decode())
  

Pruebe en línea

os.popen() es la forma más fácil y segura de ejecutar un comando. Puede ejecutar cualquier comando que ejecute en la línea de comando. Además, también podrá capturar la salida del comando utilizando os.popen().read()

Puedes hacerlo así:

import os
output = os.popen('Your Command Here').read()
print (output)
 

Un ejemplo en el que enumera todos los archivos en el directorio actual:

import os
output = os.popen('ls').read()
print (output)
# Outputs list of files in the directory
 

LA MAYORÍA DE LOS CASOS:

Para la mayoría de los casos, un pequeño fragmento de código como este es todo lo que necesitará :

 import subprocess
import shlex

source = "test.txt"
destination = "test_copy.txt"

base = "cp {source} {destination}'"
cmd = base.format(source=source, destination=destination)
subprocess.check_call(shlex.split(cmd))
  

Es limpio y simple .

subprocess.check_call ejecutar comando con argumentos y esperar comando para completar.

shlex.split divide el cmd de la cadena utilizando una sintaxis similar a la del shell

RESTO DE LOS CASOS:

Si esto no funciona para algún comando específico, lo más probable es que tenga un problema con intérpretes de línea de comandos . El sistema operativo eligió el predeterminado que no es adecuado para su tipo de programa o no pudo encontrar uno adecuado en la ruta ejecutable del sistema.

Ejemplo :

Uso del operador de redirección en un sistema Unix

 input_1 = "input_1.txt"
input_2 = "input_2.txt"
output = "merged.txt"
base_command = "/bin/bash -c 'cat {input} > {output}'"

base_command.format(input_1, output=output_1)
subprocess.check_call(shlex.split(base_command))

base_command.format(input_1, output=output_2)
subprocess.check_call(shlex.split(base_command))
  

Como se indica en El zen de Python : Explícito es mejor que implícito

Entonces, si usa una función Python> = 3.6, se vería así:

 import subprocess
import shlex

def run_command(cmd_interpreter: str, command: str) -> None:
    base_command = f"{cmd_interpreter} -c '{command}'"
    subprocess.check_call(shlex.split(base_command)

  

import os
os.system('testing')
 

os es una biblioteca de python, por lo que es muy importante importar al hacer cualquier prueba.