¿Cómo ejecutar un programa o llamar a un comando del sistema?

5433

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

0
5223

Utilice el subprocessmódulo en la biblioteca estándar:

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

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

Incluso la documentación paraos.system recomienda usar en su subprocesslugar:

The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.

En Python 3.4 y versiones anteriores, use en subprocess.calllugar de .run:

subprocess.call(["ls", "-l"])
3
  • 5
    ¿Hay alguna forma de utilizar la sustitución de variables? Es decir, traté de hacerlo echo $PATHusando call(["echo", "$PATH"]), pero simplemente se 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. 1 de septiembre de 2015 a las 23:17
  • @KevinWheeler Tendrás que usar shell=Truepara que eso funcione. 2 de septiembre de 2015 a las 20:38
  • 60
    @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
    11/11/15 a las 20:24
3165

A continuación, se muestra 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étera. Por otro lado, esto también le permite ejecutar comandos que son simplemente comandos de shell y no programas realmente externos. Consulte la documentación .

  2. stream = os.popen("some_command with args")hará lo mismo que os.systemexcepto que le brinda 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 manera ligeramente diferente. Si pasa todo como una cadena, entonces su comando se pasa al shell; si los pasa como una lista, entonces no necesita preocuparse por escapar de nada. Consulte la documentación .

  3. La Popenclase del subprocessmódulo. Está pensado como 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ías:

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

    en lugar de

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

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

  4. 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 proporcione el código de retorno. Por ejemplo:

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

    Consulte la documentación .

  5. 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.

  6. El osmódulo 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 plenamente en alguna parte de la cadena que pase. Por ejemplo, si un usuario está ingresando alguna / cualquier parte de la cadena. Si no está seguro, utilice estos métodos solo con constantes. Para darle una pista de las implicaciones, considere este código:

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

e imagina que el usuario ingresa algo " my mama didnt love me && rm -rf /" que podría borrar todo el sistema de archivos.

6
  • 37
    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. El lema más conocido de Perl es" Hay más de una manera de hacerlo ". Python está diseñado para tener una forma obvia de hacerlo" Parece que debería ser ¡La otra manera! En Perl, solo conozco dos formas de ejecutar un comando: usando back-tick o open.
    Jean
    26 de mayo de 2015 a las 21:16
  • 18
    Si usa Python 3.5+, use subprocess.run(). docs.python.org/3.5/library/subprocess.html#subprocess.run
    phoenix
    7/10/15 a las 16:37
  • 8
    Lo que normalmente se necesita saber es qué se hace con STDOUT y STDERR del proceso hijo, porque si se ignoran, bajo algunas condiciones (bastante comunes), eventualmente el proceso hijo emitirá una llamada al sistema para escribir en STDOUT (¿STDERR también?) eso excedería el búfer de salida proporcionado para el proceso por el sistema operativo, y el sistema operativo hará que se bloquee hasta que algún proceso lea desde ese búfer. Entonces, con las formas actualmente recomendadas subprocess.run(..), ¿qué significa exactamente "Esto no captura stdout o stderr de forma predeterminada". ¿implicar? ¿ subprocess.check_output(..)Y STDERR? 1 de junio de 2016 a las 10:44
  • ¿Cuál de los comandos que recomendó bloquear mi script? 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. 24 oct 2017 a las 19:08
  • 11
    Podría decirse que esto es al revés. La mayoría de las personas solo necesitan subprocess.run()o sus hermanos mayores subprocess.check_call()et al. Para los casos en los que estos no son suficientes, consulte subprocess.Popen(). os.popen()tal vez no debería ser mencionado en absoluto, o venir incluso después de "hackear su propio código fork / exec / spawn". 3 dic 2018 a las 6:00
399

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

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

5
  • 54
    .readlines()lee todas las líneas a la vez, es decir, se bloquea hasta que el subproceso sale (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,
    jfs
    16/11/12 a las 14:12
  • 4
    ¿Podría explicar lo que quiere decir con "si no hay problemas de almacenamiento en búfer"? Si el proceso se bloquea definitivamente, la llamada al subproceso también se bloquea. Lo mismo podría suceder también con mi ejemplo original. ¿Qué más podría pasar con respecto al almacenamiento en búfer?
    EmmEff
    17/11/12 a las 13:25
  • 19
    el proceso hijo puede usar búfer de bloques en modo no interactivo en lugar de búfer de línea, por lo que p.stdout.readline()(nota: no sal final) no verá ningún dato hasta que el hijo llene 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 simplemente una tubería (popen ())? . Se proporcionan algunas soluciones en esta respuesta (pexpect, pty, stdbuf)
    jfs
    17/11/12 a las 13:51
  • 6
    el problema del almacenamiento en búfer solo importa si desea una salida en tiempo real y no se aplica a su código que no imprime nada hasta que se reciben todos los datos
    jfs
    17/11/12 a las 13:53
  • 8
    Esta respuesta estuvo bien para su época, pero ya no deberíamos recomendar Popenpara tareas simples. Esto también especifica innecesariamente shell=True. Pruebe una de las subprocess.run()respuestas. 3 de diciembre de 2018 a las 5:39
259

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

Suponga que desea iniciar una tarea larga desde un script CGI. Es decir, el proceso hijo debería vivir más 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 al subproceso' hasta que termine longtask.py. Pero no está claro qué sucede después de la línea "algo más de código aquí" del ejemplo.

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

En Windows (Windows XP), el proceso principal no finalizará hasta que longtask.py haya terminado 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 el indicador de creación de proceso DETACHED_PROCESS a la función CreateProcess subyacente en la API de Windows. Si tiene instalado pywin32, puede importar el indicador desde el módulo win32process, de lo contrario, debe definirlo usted mismo:

DETACHED_PROCESS = 0x00000008

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

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

En FreeBSD tenemos otro problema: cuando finaliza el proceso padre, 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 comprobado el código en otras plataformas y no conozco las razones del comportamiento en FreeBSD. Si alguien lo sabe, comparta sus ideas. Buscar en Google sobre el inicio de procesos en segundo plano en Python aún no arroja ninguna luz.

12
  • 3
    es posible que también necesite la marca CREATE_NEW_PROCESS_GROUP. Ver a Popen esperando el proceso hijo incluso cuando el hijo inmediato ha terminado
    jfs
    16/11/12 a las 14:16
  • 2
    Veo que import subprocess as sp;sp.Popen('calc')no estoy esperando a que se complete el subproceso. Parece que las banderas de creación no son necesarias. ¿Qué me estoy perdiendo? 27/10/2014 a las 21:01
  • 9
    Lo siguiente es incorrecto: "[o] n windows (win xp), el proceso principal 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). 27/10/15 a las 0:27
  • 3
    No quise decir que la ejecución como un proceso independiente sea incorrecta. Dicho esto, es posible que deba configurar los identificadores estándar para archivos, tuberías o os.devnullporque algunos programas de consola se cierran con un error de lo contrario. Cree una nueva consola cuando desee que el proceso secundario interactúe con el usuario al mismo tiempo que el proceso principal. Sería confuso intentar hacer ambas cosas en una sola ventana. 27/10/15 a las 17:37
  • 4
    ¿No existe una forma independiente del sistema operativo de ejecutar el proceso en segundo plano? 24 feb 2019 a las 19:05
180
import os
os.system("your command")

Tenga en cuenta que esto es peligroso, ya que el comando no se limpia. Dejo que usted busque en 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.

4
  • 13
    No tengo idea de lo que quise decir hace casi una década (¡verifique la fecha!), Pero si tuviera que adivinar, sería que no se realizó ninguna validación.
    nimish
    6/06/18 a las 16:01
  • 2
    Esto ahora debería señalar subprocesscomo una solución un poco más versátil y portátil. La ejecución de comandos externos es, por supuesto, intrínsecamente intransitable (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 intrínsecamente inseguro. 3 de diciembre de 2018 a las 5:11
  • 2
    Tenga en cuenta la marca de tiempo de este tipo: la respuesta "correcta" tiene 40 veces los votos y es la respuesta n. ° 1.
    nimish
    3 dic. 18 a las 18:41
  • La única solución que funcionó para mí para ejecutar cosas de NodeJS. 29/10/19 a las 20:49
166

Recomendaría usar el módulo de subproceso en lugar de os.system porque hace un escape de shell para usted y, por lo tanto, es mucho más seguro.

subprocess.call(['ping', 'localhost'])
2
  • Si desea crear una lista a partir de un comando con parámetros , una lista que se puede usar con subprocesscuándo shell=False, utilice shlex.splitpara una manera fácil de hacer esto 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 ) 20 de septiembre de 2018 a las 18:07
  • 12
    Esto es incorrecto: " hace que el shell se escape por ti 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. 4 de diciembre de 2018 a las 8:36
158
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.

2
  • 13
    popen está en desuso a favor del subproceso . 8 de agosto de 2014 a las 0:22
  • También puede guardar su resultado con la llamada os.system, ya que funciona como el propio shell de UNIX, como por ejemplo os.system ('ls -l> test2.txt') 7 de nov. De 2017 a las 23:19
116

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 cómo llamar a un comando externo. El comando que utilicé como ejemplo es ls -l(enumerar todos los archivos). Si desea obtener más información sobre alguna de las bibliotecas que enumeré y vinculé la documentación para cada una de ellas.

Fuentes

Estas son todas las bibliotecas

Con suerte, esto le ayudará a tomar una decisión sobre qué biblioteca utilizar :)

subproceso

El subproceso le permite llamar a comandos externos y conectarlos a sus conductos 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

usted

os se utiliza para "funcionalidad dependiente del sistema operativo". También se puede utilizar para llamar a comandos externos con os.systemy os.popen(Nota: también hay un subprocess.popen). os siempre ejecutará el shell y es una alternativa simple para las personas que no lo necesitan o 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

dirigir

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

esperar

pexpect le permite generar aplicaciones secundarias, controlarlas y encontrar patrones en su salida. Esta es una mejor alternativa al subproceso para comandos que esperan un tty en Unix.

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

tela

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

Envoy se conoce como "subproceso para humanos". Se utiliza como envoltorio de conveniencia alrededor del subprocessmódulo.

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

comandos

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

0
83

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 está usando 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 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 subprocessenvoltorio. Es multiplataforma, es decir, funciona tanto en Windows como en sistemas similares a Unix. Instalar por pip install plumbum.

Otra biblioteca popular es sh :

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

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

82

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)
0
80

Consulte también la biblioteca de 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')
0
78

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 .

If shell is True, the specified command will be executed through the shell. This can be useful if you are using Python primarily for the enhanced control flow it offers over most system shells and still want convenient access to other shell features such as shell pipes, filename wildcards, environment variable expansion, and expansion of ~ to a user’s home directory. However, note that Python itself offers implementations of many shell-like features (in particular, glob, fnmatch, os.walk(), os.path.expandvars(), os.path.expanduser(), and shutil).

2
  • 2
    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 sencilla y legible de hacerlo es subprocess.check_output("ls -l /dev/null".split()). 30 de enero de 2018 a las 18:18
  • Como la respuesta menciona vagamente, y muchas otras respuestas en esta página se explican con más detalle, puede pasar una lista o con shell=Trueuna sola cadena que el shell luego se encarga de analizar y ejecutar. Usar simple .split()está bien en las circunstancias que menciona, pero los principiantes generalmente no comprenden los matices; probablemente sea mejor recomendar shlex.split()cuál maneja correctamente los escapes de las comillas y la barra invertida. 9 de junio a las 19:39
63

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 la de Envoy. (Sin embargo, la instalación de tuberías no es tan sencilla. 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)

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

Capturar salida:

>>> 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. Envoy es un subproceso para humanos.

Ejemplo de uso del 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
''

Ponga cosas alrededor también:

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

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

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

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()
2
  • 4
    Creo que es aceptable para comandos codificados de forma rígida, si aumenta la legibilidad. 2 abr 14 a las 13:07
  • Una explicación estaría en orden. Por ejemplo, ¿cuál es la idea / esencia? 7 de abril a las 17:18
51

Usar subproceso .

... o para un comando muy simple:

import os
os.system('cat testfile')
49

How to execute a program or call a system command from Python

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

>>> from subprocess import run
>>> from shlex import split
>>> completed_process = run(split('python --version'))
Python 3.8.8
>>> completed_process
CompletedProcess(args=['python', '--version'], returncode=0)

( runquiere una lista de argumentos de shell analizados léxicamente: esto es lo que escribiría en un shell, separado por espacios, pero no donde se citan los espacios, así que use una función especializada split, para dividir lo que literalmente escribiría en su cascarón)

¿Por qué?

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

The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.

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

>>> from subprocess import run
>>> from shlex import split
>>> completed_process = run(split('python --version'))
Python 3.8.8
>>> completed_process
CompletedProcess(args=['python', '--version'], returncode=0)

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

Como puede inferir 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 dio y el código de retorno:

>>> completed_process.args
['python', '--version']
>>> completed_process.returncode
0

Capturando salida

Si desea capturar la salida, puede pasar subprocess.PIPEal apropiado stderro stdout:

>>> from subprocess import PIPE
>>> completed_process = run(shlex.split('python --version'), stdout=PIPE, stderr=PIPE)
>>> completed_process.stdout
b'Python 3.8.8\n'
>>> completed_process.stderr
b''

Y esos atributos respectivos devuelven bytes.

Pasar 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 mediante programación. No cree cadenas mediante programación. Este es un problema de seguridad potencial. Es mejor asumir que no confía en la entrada.

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

Tenga en cuenta que solo argsdebe 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 kwargsse entregan al Popenconstructor. inputpuede ser una cadena de bytes (o unicode, si se especifica codificación o universal_newlines=True) que se canalizará al stdin del subproceso.

La documentación describe timeout=y check=Truemejor de lo que pude:

The timeout argument is passed to Popen.communicate(). If the timeout expires, the child process will be killed and waited for. The TimeoutExpired exception will be re-raised after the child process has terminated.

If check is true, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured.

y este ejemplo check=Truees mejor que el que se me ocurrió:

>>> 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 ampliada, 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. Así que pase los argumentos restantes como argumentos de palabras clave.

Popen

¿Cuándo se usa Popenen su lugar? Me costaría encontrar un caso de uso basado solo en los argumentos. PopenSin embargo, el uso directo de le daría acceso a sus métodos, incluidos poll'send_signal', 'terminate' y 'wait'.

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=True,
             shell=False, cwd=None, env=None, universal_newlines=None,
             startupinfo=None, creationflags=0,
             restore_signals=True, start_new_session=False,
             pass_fds=(), *, user=None, group=None, extra_groups=None,
             encoding=None, errors=None, text=None, umask=-1, pipesize=-1):

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=None, startupinfo=None, creationflags=0, 
restore_signals=True, start_new_session=False, pass_fds=(), *, group=None, 
extra_groups=None, user=None, umask=-1, encoding=None, errors=None, 
text=None)

Execute a child program in a new process. On POSIX, the class uses os.execvp()-like behavior to execute the child program. On Windows, the class uses the Windows CreateProcess() function. The arguments to Popen are as follows.

La comprensión de la documentación restante Popense dejará como ejercicio para el lector.

1
40

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

Obtenga más información aquí .

1
  • 3
    Si bien estoy de acuerdo con la recomendación general, subprocessno elimina todos los problemas de seguridad y tiene algunos problemas propios. 3 de diciembre de 2018 a las 5:36
37

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
1
  • Una explicación estaría en orden. 7 de abril a las 17:29
33

A partir de Python 3.7.0 lanzado el 27 de junio de 2018 ( https://docs.python.org/3/whatsnew/3.7.html ) , puede lograr el resultado deseado de la manera más poderosa e igualmente simple. Esta respuesta tiene la intención de mostrarle el resumen esencial de varias opciones de manera breve. Para obtener respuestas detalladas, consulte las otras.


TL; DR en 2021

La gran ventaja de os.system(...)fue su sencillez. subprocesses mejor y aún más fácil de usar, especialmente a partir de Python 3.5 .

import subprocess
subprocess.run("ls -a", shell=True)

Nota: esta es la respuesta exacta a su pregunta: ejecutar un comando

like in a shell


Forma preferida

Si es posible, elimine la sobrecarga del shell y ejecute el comando directamente (requiere una lista).

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

Pasa los argumentos del programa en una lista. No incluya \"-escaping para argumentos que contengan espacios.


Casos de uso avanzados

Comprobación de la salida

El siguiente código habla por sí solo:

import subprocess
result = subprocess.run(["ls", "-a"], capture_output=True, text=True)
if "stackoverflow-logo.png" in result.stdout:
    print("You're a fan!")
else:
    print("You're not a fan?")

result.stdoutes toda la salida del programa normal, excluidos los errores . Lea result.stderrpara obtenerlos.

capture_output=True- activa la captura. De lo contrario result.stderry result.stdoutlo sería None. Disponible desde Python 3.7 .

text=True- un argumento de conveniencia agregado en Python 3.7 que convierte los datos binarios recibidos en cadenas de Python con las que puede trabajar fácilmente.

Verificando el código de retorno

Hacer

if result.returncode == 127: print("The program failed for some weird reason")
elif result.returncode == 0: print("The program succeeded")
else: print("The program failed unexpectedly")

Si solo desea verificar si el programa tuvo éxito (código de retorno == 0) y, de lo contrario, lanzar una excepción, hay una función más conveniente:

result.check_returncode()

Pero es Python, por lo que hay un argumento aún más conveniente checkque hace lo mismo automáticamente por ti:

result = subprocess.run(..., check=True)

stderr debe estar dentro de stdout

Es posible que desee tener todos los resultados del programa dentro de stdout, incluso los errores. Para lograr esto, ejecute

result = subprocess.run(..., stderr=subprocess.STDOUT)

result.stderrentonces será Noney result.stdoutcontendrá todo.

Usando shell = False con una cadena de argumentos

shell=Falseespera una lista de argumentos. Sin embargo, puede dividir una cadena de argumentos por su cuenta usando shlex.

import subprocess
import shlex
subprocess.run(shlex.split("ls -a"))

Eso es todo.

Problemas comunes

Es muy probable que haya comenzado a usar Python cuando se encuentre con esta pregunta. Veamos algunos problemas comunes.

FileNotFoundError: [Errno 2] No such file or directory: 'ls -a': 'ls -a'

Está ejecutando un subproceso sin shell=True. Utilice una lista ( ["ls", "-a"]) o un conjunto shell=True.

TypeError: [...] NoneType [...]

Comprueba que hayas configurado capture_output=True.

TypeError: a bytes-like object is required, not [...]

Siempre recibe resultados de bytes de su programa. Si desea trabajar con él como una cadena normal, configure text=True.

subprocess.CalledProcessError: Command '[...]' returned non-zero exit status 1.

Su comando no se ejecutó correctamente. Puede deshabilitar la verificación del código de retorno o verificar la validez real de su programa.

TypeError: init() got an unexpected keyword argument [...]

Es probable que esté utilizando una versión de Python anterior a la 3.7.0; actualícelo al más reciente disponible. De lo contrario, hay otras respuestas en esta publicación de Stack Overflow que le muestra soluciones alternativas más antiguas.

5
  • 1
    "La gran ventaja de os.system (...) fue su simplicidad. El subproceso es mejor" - ¿cómo es mejor el subproceso? Estoy felizmente usando os.system, no estoy seguro de cómo cambiar a subproceso y recordar shell=Truebeneficios adicionales me beneficia. ¿Qué tipo de cosa es mejor en el subproceso? 26 mar a las 9:14
  • 1
    Tiene razón en que os.system(...)es una opción razonable para ejecutar comandos en términos de ejecución simple "ciega". Sin embargo, los casos de uso son bastante limitados: tan pronto como desee capturar la salida, debe usar una biblioteca completamente diferente y luego comenzar a tener ambos: subproceso y sistema operativo para casos de uso similares en su código. Prefiero mantener el código limpio y usar solo uno de ellos. En segundo lugar, y me he puesto esa sección en la parte superior, pero el TL; DR tiene que responder a la pregunta exactamente , se debe no utilizar shell=True, pero en su lugar lo que he escrito en la Preferred Waysección.
    fameman
    27 mar a las 11:30
  • 1
    El problema con os.system(...)y shell=Truees que está generando un nuevo proceso de shell, solo para ejecutar su comando. Esto significa que debe realizar un escape manual, que no es tan simple como podría pensar, especialmente cuando se dirige tanto a POSIX como a Windows. Para la entrada proporcionada por el usuario, esta es una opción prohibida (solo imagine que el usuario ingresó algo con "comillas; también tendría que escapar de ellas). Además, el proceso de shell en sí mismo podría cargar código que no necesita; no solo retrasa el programa, sino que también puede provocar efectos secundarios inesperados, que terminan con un código de retorno incorrecto.
    fameman
    27 de marzo a las 11:34
  • 2
    Resumiendo, os.system(...)es válido usar, de hecho. Pero tan pronto como esté escribiendo algo más que un script auxiliar rápido de Python, le recomiendo que opte por subprocess.run sin shell=True. Para obtener más información sobre los inconvenientes de os.system, me gustaría proponerle que lea esta respuesta SO: stackoverflow.com/a/44731082/6685358
    fameman
    27 de marzo a las 11:35
  • ¡Gracias! Quería editar "mejor" para incluir ese enlace, pero recibí un error sobre la cola de edición completa. 27 mar a las 15:01
31

Puede ser así de simple:

import os
cmd = "your command"
os.system(cmd)
1
  • 2
    Esto no señala los inconvenientes, que se explican con mucho más detalle en PEP-324 . La documentación para os.systemrecomienda explícitamente evitarlo a favor de subprocess. 3 dic 2018 a las 5:02
30

Usar:

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.

1
  • 2
    también está en desuso. usar subproceso 9/12/15 a las 18:13
25

Aquí hay otra diferencia que no se mencionó 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.

Una más: (NOTA: kwrite se comporta de manera diferente a otras aplicaciones. Si prueba 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 cierra kwrite. Para superar eso, lo intenté en su lugar os.system(konsole -e kwrite). Esta vez el programa siguió 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 borde más a la izquierda del árbol).

2
  • 1
    ¿Qué quiere decir con "Cualquiera ejecuta kwrite sin ser un subproceso" ? 3 de junio de 2018 a las 20:14
  • De hecho, es desconcertante que se subprocessejecute un subproceso. 9 de junio a las 19:40
25

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

23

subprocess.check_calles conveniente si no desea probar los valores devueltos. Lanza una excepción en cualquier error.

23

Tiendo a usar 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)
19

Escribí una biblioteca para esto, shell.py .

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

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

En Windows, puede importar el subprocessmódulo y ejecutar comandos externos llamando subprocess.Popen(), subprocess.Popen().communicate()y subprocess.Popen().wait()como se muestra a continuación:

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

Producción:

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

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 termine el script de Python), puede usar una cola simple como administrador de tareas o el comando at .

Un ejemplo con el spooler de tareas:

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

Notas sobre el spooler de tareas ( ts):

  1. Puede establecer el número de procesos simultáneos 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, agréguelo a su ruta y listo.

1
  • 1
    tsno es estándar en ninguna distribución que conozca, aunque el puntero a ates ligeramente útil. Probablemente también deberías mencionar batch. Como en otros lugares, la os.system()recomendación probablemente debería al menos mencionar que subprocesses su reemplazo recomendado. 3 de diciembre de 2018 a las 5:43
17

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 a subprocess.Popen .

17

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
1
  • No debería recomendar os.popen()en 2016. El script Awk podría reemplazarse fácilmente con código Python nativo. 3 de diciembre de 2018 a las 5:49