una - os.system python ejemplos




Llamando un comando externo en Python (20)

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


Llamando un comando externo en Python

Simple, use subprocess.run , que devuelve un objeto CompletedProcess :

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

¿Por qué?

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

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

Este es un ejemplo del uso más simple posible, y hace exactamente lo que se le pide:

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

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

Como puede inferir del ejemplo anterior, stdout y stderr se canalizan a su propia 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

Captura de salida

Si desea capturar la salida, puede pasar subprocess.PIPE al stderr o stdout apropiado:

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

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

Pasar una lista de comandos

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

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

Tenga en cuenta que solo los args deben pasarse de forma posicional.

Firma completa

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

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

Los popenargs y los kwargs son dados al constructor de Popen . input puede ser una cadena de bytes (o unicode, si se especifica la codificación o universal_newlines=True ) que se canalizará a la entrada estándar del subproceso.

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

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

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

y este ejemplo para check=True es mejor que uno que podría encontrar:

>>> 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 Expandida

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

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

Tenga en cuenta que esto indica que solo la lista de argumentos debe pasarse de manera posicional. Así que pase los argumentos restantes como argumentos de palabras clave.

Popen

Cuando se usa Popen en Popen lugar? Me costaría encontrar un caso de uso basado solo en los argumentos. Sin embargo, el uso directo de Popen le daría acceso a sus métodos, incluidos poll , 'send_signal', 'terminate' y 'wait'.

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

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

Pero más informativa es la documentación de Popen :

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

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

La comprensión de la documentación restante en Popen se dejará como un ejercicio para el lector.


Actualizar:

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 la de Envoy. (Sin embargo, la canalización no es tan sencilla. Vea esta pregunta para saber cómo ).

Aquí hay algunos ejemplos de la documentación .

Ejecutar un proceso:

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

Levantar 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 https://github.com/kennethreitz/envoy . Es una envoltura para el subproceso, que a su vez apunta a reemplazar los módulos y funciones más antiguos. Enviado es subproceso para los humanos.

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

Pipe cosas alrededor también:

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

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

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

Algunos consejos para separar el proceso hijo del que llama (iniciar el proceso hijo en segundo plano).

Supongamos que desea iniciar una tarea larga desde un script CGI, es decir, el proceso hijo debería durar más que el proceso de ejecución del script CGI.

El ejemplo clásico de los documentos del módulo de subproceso es:

import subprocess
import sys

# some code here

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

# some more code here

La idea aquí es que no desea esperar en la línea 'subproceso de llamada' 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 primero enfrenté el problema en Windows.

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

La solución es pasar el indicador de creación de proceso DETACHED_PROCESS a la función CreateProcess subyacente en la API win. 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 debajo observa que la marca semánticamente correcta es CREATE_NEW_CONSOLE (0x00000010) * /

En freebsd tenemos otro problema: cuando finaliza el proceso principal, también finaliza los procesos secundarios. Y eso tampoco es lo que quieres en el 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 los motivos del comportamiento en freebsd. Si alguien sabe, por favor comparte tus ideas. Buscar en Google al iniciar procesos en segundo plano en Python no arroja ninguna luz todavía.


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 realmente puede ejecutar varios comandos a la vez de esta manera y configurar tuberías y redirección de entrada / salida. Por ejemplo:

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

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

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

  3. La clase de Popen del módulo de subprocess . Esto pretende ser un reemplazo para os.popen pero tiene el inconveniente de ser un poco más complicado por el hecho 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 función de call desde el módulo de subprocess . Básicamente, es igual que la clase Popen y toma todos los mismos argumentos, pero simplemente espera hasta que el comando se completa y te da 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 función subprocess.run , que es muy parecida a la anterior pero aún más flexible y devuelve un objeto CompletedProcess cuando el comando termina de ejecutarse.

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

El módulo de subprocess probablemente debería ser lo que usas.

Finalmente, tenga en cuenta que para todos los métodos en los que pase el comando final para que sea ejecutado por el shell como una cadena y usted es responsable de evitarlo. Hay serias implicaciones de seguridad si alguna parte de la cadena que pasa no puede ser completamente confiable. Por ejemplo, si un usuario ingresa alguna parte de la cadena. Si no está seguro, solo use estos métodos con constantes. Para darte una pista de las implicaciones, considera este código:

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

e imagina que el usuario ingresa "mi mamá no me ama && rm -rf /".


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

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

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

Hay muchas bibliotecas diferentes que te permiten llamar comandos externos con Python. Para cada biblioteca, proporcioné una descripción y mostré un ejemplo de cómo llamar a un comando externo. El comando que usé como ejemplo es ls -l (listar todos los archivos). Si desea obtener más información sobre cualquiera de las bibliotecas que he enumerado y vinculado la documentación de cada una de ellas.

Fuentes:

Estas son todas las bibliotecas:

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

subproceso

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

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

os

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

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

sh

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

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

plomo

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

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

espere

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 Python 2.5 y 2.7. Te permite ejecutar comandos de shell locales y remotos. Fabric es una alternativa simple para ejecutar comandos en un shell seguro (SSH)

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

enviado

Enviado es conocido como "subproceso para los humanos". Se utiliza como un envoltorio de conveniencia alrededor del módulo de subprocess .

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

comandos

commands contienen funciones de envoltorio para os.popen , pero se han eliminado de Python 3 ya que el subprocess es una mejor alternativa.

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


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

from subprocess import call
call(["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 módulo de subproceso sobre el os.system () alternativo:

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

La sección " Reemplazar funciones antiguas con el módulo de subproceso " en la documentación del subproceso puede tener algunas recetas útiles.

Documentación oficial del módulo de subproceso :


Normalmente uso:

import subprocess

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

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



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 de shell .

Si el shell es True , el comando especificado se ejecutará a través del shell. Esto puede ser útil si está utilizando Python principalmente para el flujo de control mejorado que ofrece en la mayoría de los shells del sistema y aún desea un acceso conveniente a otras funciones del shell, como shells, comodines de nombres de archivos, expansión de variables de entorno y expansión de ~ a la casa del usuario. directorio. Sin embargo, tenga en cuenta que Python ofrece implementaciones de muchas características similares a shell (en particular, glob , fnmatch , os.walk() , os.path.expandvars() , os.path.expanduser() y shutil ).


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

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

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

shlex a usar el subproceso junto con shlex (para manejar el escape de cadenas citadas):

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

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

Obtenga más información here .


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


Para obtener el ID de red del neutrón de pila abierta:

#!/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

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 .


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

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





external