¿Cómo se llama un comando externo (como si lo hubiera escrito en el shell de Unix o en el símbolo del sistema de Windows) desde un script de Python?
¿Cómo se llama un comando externo (como si lo hubiera escrito en el shell de Unix o en el símbolo del sistema de Windows) desde un script de Python?
Respuestas:
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 el stdout
,stderr
, el código "real" de estado, un mejor control de errores, etc ...).
La documentación oficial recomienda el subprocess
módulo sobre la alternativa os.system()
:
El
subprocess
módulo proporciona instalaciones más potentes para generar nuevos procesos y recuperar sus resultados; usar ese módulo es preferible a usar esta función [os.system()
].
La Reemplazo de funciones antiguas con la sección Módulo de subproceso en la subprocess
documentación puede tener algunas recetas útiles.
Para versiones de Python anteriores a 3.5, use call
:
import subprocess
subprocess.call(["ls", "-l"])
shell=True
para que eso funcione.
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
for
bucle, ¿cómo lo hago sin que bloquee mi script de Python? No me importa la salida del comando, solo quiero ejecutar muchos de ellos.
subprocess
cuándo shell=False
, luego use shlex.split
para una manera fácil de hacerlo docs.python.org/2/library/shlex.html#shlex.split
Aquí hay un resumen de las formas de llamar a programas externos y las ventajas y desventajas de cada uno:
os.system("some_command with args")
pasa el comando y los argumentos al shell de su sistema. Esto es bueno porque en realidad puede ejecutar múltiples comandos a la vez de esta manera y configurar tuberías y redirección de entrada / salida. Por ejemplo:
os.system("some_command < input_file | another_command > output_file")
Sin embargo, aunque esto es conveniente, debe manejar manualmente el escape de caracteres de shell como espacios, etc. Por otro lado, esto también le permite ejecutar comandos que son simplemente comandos de shell y no programas externos. Ver la documentación .
stream = os.popen("some_command with args")
hará lo mismo, 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. Ver la documentación .
La Popen
clase del subprocess
módulo. Esto pretende ser un reemplazo 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 vez de:
print os.popen("echo Hello World").read()
pero es bueno tener todas las opciones allí en una clase unificada en lugar de 4 funciones popen diferentes. Ver la documentación .
La call
función del subprocess
módulo. Esto es básicamente como la Popen
clase y toma todos los mismos argumentos, pero simplemente espera hasta que el comando se complete y le dé el código de retorno. Por ejemplo:
return_code = subprocess.call("echo Hello World", shell=True)
Ver la documentación .
Si está en Python 3.5 o posterior, puede usar la nueva subprocess.run
función, que es muy parecida a la anterior pero aún más flexible y devuelve un CompletedProcess
objeto cuando el comando termina de ejecutarse.
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 subprocess
módulo probablemente debería ser lo que usa.
Finalmente, tenga en cuenta que para todos los métodos en los que pasa el comando final para que el shell lo ejecute como una cadena y usted es responsable de escapar de él. Existen serias implicaciones de seguridad si no se puede confiar completamente en alguna parte de la cadena que pasa. Por ejemplo, si un usuario está ingresando alguna / cualquier parte de la cadena. Si no está seguro, solo use estos métodos con constantes. Para darle una pista de las implicaciones, considere este código:
print subprocess.Popen("echo %s " % user_input, stdout=PIPE).stdout.read()
e imagine que el usuario ingresa algo "mi mamá no me amaba && rm -rf /" que podría borrar todo el sistema de archivos.
open
.
subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.run
subprocess.run(..)
, ¿qué hace exactamente ? Esto no captura stdout o stderr de manera predeterminada. ¿implicar? ¿Qué pasa con subprocess.check_output(..)
STDERR?
echo
frente de la cadena pasada a Popen
? Entonces el comando completo será echo my mama didnt love me && rm -rf /
.
subprocess.run()
o sus hermanos mayores subprocess.check_call()
et al. Para los casos en que estos no son suficientes, vea subprocess.Popen()
. os.popen()
tal vez no debería mencionarse en absoluto, o incluso después de "piratear su propio código fork / exec / spawn".
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 stdout
datos en la tubería. De hecho, simplemente puede omitir esos parámetros ( stdout=
y stderr=
) y se comportará como os.system()
.
.readlines()
lee todas las líneas a la vez, es decir, bloquea hasta que sale el subproceso (cierra el extremo de la tubería). Para leer en tiempo real (si no hay problemas de almacenamiento en búfer) puede:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(nota: no s
al final) no verá ningún dato hasta que el hijo llene su almacenamiento intermedio. Si el niño no produce muchos datos, la salida no será en tiempo real. Vea la segunda razón en P: ¿Por qué no usar una tubería (popen ())? . En esta respuesta se proporcionan algunas soluciones (pexpect, pty, stdbuf)
Popen
para tareas simples. Esto también especifica innecesariamente shell=True
. Prueba una de las subprocess.run()
respuestas.
Algunas sugerencias para separar el proceso hijo del que llama (iniciando el proceso hijo en segundo plano).
Suponga que desea comenzar una tarea larga desde un script CGI. Es decir, el proceso secundario debería vivir más tiempo que el proceso de ejecución del script CGI.
El ejemplo clásico de la documentación del módulo de subproceso es:
import subprocess
import sys
# Some code here
pid = subprocess.Popen([sys.executable, "longtask.py"]) # Call subprocess
# Some more code here
La idea aquí es que no desea esperar en la línea 'llamar subproceso' hasta que finalice longtask.py. Pero no está claro qué sucede después de la línea 'más código aquí' del ejemplo.
Mi plataforma de destino era FreeBSD, pero el desarrollo estaba en Windows, así que enfrenté el problema en Windows primero.
En Windows (Windows XP), el proceso padre no finalizará hasta que longtask.py haya finalizado su trabajo. No es lo que quieres en un script CGI. El problema no es específico de Python; En la comunidad PHP, los problemas son los mismos.
La solución es pasar DETACHED_PROCESS Indicador de creación de procesos a la función CreateProcess subyacente en la API de Windows. Si tiene instalado pywin32, puede importar el indicador desde el módulo de proceso win32, de lo contrario, debe definirlo usted mismo:
DETACHED_PROCESS = 0x00000008
pid = subprocess.Popen([sys.executable, "longtask.py"],
creationflags=DETACHED_PROCESS).pid
/ * UPD 2015.10.27 2015.10.27 @eryksun en un comentario debajo de las notas, que el indicador semánticamente correcto es CREATE_NEW_CONSOLE (0x00000010) * /
En FreeBSD tenemos otro problema: cuando el proceso padre finaliza, también finaliza los procesos hijos. Y eso tampoco es lo que quieres en un script CGI. Algunos experimentos mostraron que el problema parecía estar en compartir sys.stdout. Y la solución de trabajo fue la siguiente:
pid = subprocess.Popen([sys.executable, "longtask.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
No he comprobado el código en otras plataformas y no sé los motivos del comportamiento en FreeBSD. Si alguien lo sabe, por favor comparta sus ideas. Buscar en Google al iniciar procesos en segundo plano en Python aún no arroja luz.
DETACHED_PROCESS
de creationflags
evita 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).
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.
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.
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.
Recomiendo utilizar el módulo de subproceso en lugar de os.system porque escapa de shell por usted y, por lo tanto, es mucho más seguro.
subprocess.call(['ping', 'localhost'])
subprocess
cuándo shell=False
, luego use shlex.split
una manera fácil de hacerlo docs.python.org/2/library/shlex.html#shlex.split ( es la forma recomendada de acuerdo con los documentos docs.python.org/2/library/subprocess.html#popen-constructor )
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.
Hay muchas bibliotecas diferentes que le permiten llamar a comandos externos con Python. Para cada biblioteca he dado una descripción y he mostrado un ejemplo de invocar un comando externo. El comando que utilicé como ejemplo es ls -l
(enumerar todos los archivos). Si desea obtener más información sobre cualquiera de las bibliotecas que he enumerado y vinculado la documentación de cada una de ellas.
Fuentes:
Estas son todas las bibliotecas:
Esperemos que esto te ayude a tomar una decisión sobre qué biblioteca usar :)
subproceso
El subproceso le permite llamar a comandos externos y conectarlos a sus canales de entrada / salida / error (stdin, stdout y stderr). El subproceso es la opción predeterminada para ejecutar comandos, pero a veces otros módulos son mejores.
subprocess.run(["ls", "-l"]) # Run command
subprocess.run(["ls", "-l"], stdout=subprocess.PIPE) # This will run the command and return any output
subprocess.run(shlex.split("ls -l")) # You can also use the shlex library to split the command
os
os se usa para "funcionalidad dependiente del sistema operativo". También se puede usar para llamar a comandos externos con os.system
y os.popen
(Nota: También hay un subproceso.popen). os siempre ejecutará el shell y es una alternativa simple para las personas que no lo necesitan o que no saben cómo usarlo subprocess.run
.
os.system("ls -l") # run command
os.popen("ls -l").read() # This will run the command and return any output
sh
sh es una interfaz de subproceso que le permite llamar a programas como si fueran funciones. Esto es útil si desea ejecutar un comando varias veces.
sh.ls("-l") # Run command normally
ls_cmd = sh.Command("ls") # Save command as a variable
ls_cmd() # Run command as if it were a function
plomo
plumbum es una biblioteca para programas Python "tipo script". Puede llamar a programas como funciones como en sh
. Plumbum es útil si desea ejecutar una tubería sin el shell.
ls_cmd = plumbum.local("ls -l") # get command
ls_cmd() # run command
pexpect
pexpect le permite generar aplicaciones secundarias, controlarlas y encontrar patrones en su salida. Esta es una mejor alternativa al subproceso para los comandos que esperan un tty en Unix.
pexpect.run("ls -l") # Run command as normal
child = pexpect.spawn('scp foo user@example.com:.') # Spawns child application
child.expect('Password:') # When this is the output
child.sendline('mypassword')
tela
fabric es una biblioteca de Python 2.5 y 2.7. Le permite ejecutar comandos de shell locales y remotos. Fabric es una alternativa simple para ejecutar comandos en un shell seguro (SSH)
fabric.operations.local('ls -l') # Run command as normal
fabric.operations.local('ls -l', capture = True) # Run command and receive output
enviado
enviado se conoce como "subproceso para los humanos". Se utiliza como una envoltura conveniente alrededor del subprocess
módulo.
r = envoy.run("ls -l") # Run command
r.std_out # get output
comandos
commands
contiene funciones de contenedor para os.popen
, pero se ha eliminado de Python 3 ya que subprocess
es una mejor alternativa.
La edición se basó en el comentario de JF Sebastian.
Siempre uso fabric
para esto cosas como:
from fabric.operations import local
result = local('ls', capture=True)
print "Content:/n%s" % (result, )
Pero esta parece ser una buena herramienta: sh
(interfaz de subproceso de Python) .
Mira un ejemplo:
from sh import vgdisplay
print vgdisplay()
print vgdisplay('-v')
print vgdisplay(v=True)
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')
Use el módulo de subproceso (Python 3):
import subprocess
subprocess.run(['ls', '-l'])
Es la forma estándar recomendada. Sin embargo, las tareas más complicadas (canalizaciones, salida, entrada, etc.) pueden ser tediosas de construir y escribir.
Nota sobre la versión de Python: si todavía usa Python 2, subprocess.call funciona de manera similar.
ProTip: shlex.split puede ayudarlo a analizar el comando para run
, call
y otras subprocess
funciones en caso de que no quiera (o no pueda) proporcionarlas en forma de listas:
import shlex
import subprocess
subprocess.run(shlex.split('ls -l'))
Si no le importan las dependencias externas, use plumbum :
from plumbum.cmd import ifconfig
print(ifconfig['wlan0']())
Es el mejor subprocess
envoltorio. Es multiplataforma, es decir, funciona tanto en sistemas Windows como Unix. Instalar por pip install plumbum
.
Otra biblioteca popular es sh :
from sh import ifconfig
print(ifconfig('wlan0'))
Sin embargo, sh
dejó de admitir Windows, por lo que ya no es tan impresionante como solía ser. Instalar por pip install sh
.
Si necesita la salida del comando que está llamando, puede usar subprocess.check_output (Python 2.7+).
>>> subprocess.check_output(["ls", "-l", "/dev/null"])
'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
También tenga en cuenta el parámetro de shell .
Si el shell es
True
, el comando especificado se ejecutará a través del shell. Esto puede ser útil si está utilizando Python principalmente para el flujo de control mejorado que ofrece sobre la mayoría de los shells del sistema y aún desea un acceso conveniente a otras características de shell, como tuberías de shell, comodines de nombre de archivo, expansión de variable de entorno y expansión de ~ a la página de inicio de un usuario directorio. Sin embargo, nota que el propio Python ofrece implementaciones de muchos de concha características (en particular,glob
,fnmatch
,os.walk()
,os.path.expandvars()
,os.path.expanduser()
, yshutil
).
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 fácil de hacerlo es subprocess.check_output("ls -l /dev/null".split())
.
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()
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 para saber cómo ).
Aquí hay algunos ejemplos de la documentación .
Ejecute un proceso:
>>> subprocess.run(["ls", "-l"]) # Doesn't capture output
CompletedProcess(args=['ls', '-l'], returncode=0)
Elevar en ejecución fallida:
>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Salida de captura:
>>> subprocess.run(["ls", "-l", "/dev/null"], stdout=subprocess.PIPE)
CompletedProcess(args=['ls', '-l', '/dev/null'], returncode=0,
stdout=b'crw-rw-rw- 1 root root 1, 3 Jan 23 16:23 /dev/null\n')
Recomiendo probar Envoy . Es un contenedor para subprocesos, que a su vez tiene como objetivo reemplazar los módulos y funciones más antiguos. El enviado es un subproceso para los humanos.
Ejemplo de uso de README :
>>> r = envoy.run('git config', data='data to pipe in', timeout=2)
>>> r.status_code
129
>>> r.std_out
'usage: git config [options]'
>>> r.std_err
''
Tubería cosas alrededor también:
>>> r = envoy.run('uptime | pbcopy')
>>> r.command
'pbcopy'
>>> r.status_code
0
>>> r.history
[<Response 'uptime'>]
os.system
está bien, pero un poco anticuado. Tampoco es muy seguro. En cambio, inténtalo subprocess
. subprocess
no llama a sh directamente y, por lo tanto, es más seguro que os.system
.
Obtenga más información aquí .
subprocess
no elimina todos los problemas de seguridad y tiene algunos problemas molestos.
Llamar a un comando externo en Python
Simple, use subprocess.run
, que devuelve un CompletedProcess
objeto:
>>> 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)
A partir de Python 3.5, la documentación recomienda subprocess.run :
El enfoque recomendado para invocar subprocesos es utilizar la función run () para todos los casos de uso que pueda manejar. Para casos de uso más avanzados, la interfaz de Popen subyacente se puede usar directamente.
Aquí hay un ejemplo del uso más simple posible, y hace exactamente lo que se le pide:
>>> import subprocess
>>> completed_process = subprocess.run('python --version')
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
>>> completed_process
CompletedProcess(args='python --version', returncode=0)
run
espera a que el comando finalice correctamente y luego devuelve un CompletedProcess
objeto. En su lugar, puede aumentar TimeoutExpired
(si le da un timeout=
argumento) o CalledProcessError
(si falla y pasa check=True
).
Como puede deducir del ejemplo anterior, stdout y stderr se canalizan a su propio stdout y stderr de forma predeterminada.
Podemos inspeccionar el objeto devuelto y ver el comando que se le dio y el código de retorno:
>>> completed_process.args
'python --version'
>>> completed_process.returncode
0
Si desea capturar la salida, puede pasar subprocess.PIPE
a la correspondiente stderr
o stdout
:
>>> cp = subprocess.run('python --version',
stderr=subprocess.PIPE,
stdout=subprocess.PIPE)
>>> cp.stderr
b'Python 3.6.1 :: Anaconda 4.4.0 (64-bit)\r\n'
>>> cp.stdout
b''
(Me parece interesante y ligeramente contradictorio que la información de la versión se ponga en stderr en lugar de stdout).
Uno podría pasar fácilmente de proporcionar manualmente una cadena de comando (como sugiere la pregunta) a proporcionar una cadena construida programáticamente. No construya cadenas mediante programación. Este es un posible problema de seguridad. Es mejor asumir que no confía en la entrada.
>>> import textwrap
>>> args = ['python', textwrap.__file__]
>>> cp = subprocess.run(args, stdout=subprocess.PIPE)
>>> cp.stdout
b'Hello there.\r\n This is indented.\r\n'
Nota solo args
debe pasarse posicionalmente.
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 popenargs
y kwargs
son dados al Popen
constructor. input
puede ser una cadena de bytes (o unicode, si especifica la codificación ouniversal_newlines=True
) que se canalizarán al stdin del subproceso.
La documentación describe timeout=
y check=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 secundario se cancelará y se esperará. La excepción TimeoutExpired se volverá a generar después de que el proceso secundario haya finalizado.
Si la comprobación es verdadera y el proceso sale con un código de salida distinto de cero, se generará una excepción CalledProcessError. Los atributos de esa excepción contienen los argumentos, el código de salida y stdout y stderr si fueron capturados.
y este ejemplo check=True
es mejor que uno que se me ocurra:
>>> subprocess.run("exit 1", shell=True, check=True) Traceback (most recent call last): ... subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1
Aquí hay una firma expandida, como se indica en la documentación:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None)
Tenga en cuenta que esto indica que solo la lista de argumentos debe pasarse posicionalmente. Entonces pase los argumentos restantes como argumentos de palabras clave.
Cuando uso Popen
en su lugar? Me gustaría encontrar un caso de uso basado solo en los argumentos. Popen
Sin embargo, el uso directo de daría acceso a sus métodos, incluidospoll
'send_signal', 'terminar' y 'esperar'.
Aquí está la Popen
firma que figura en la fuente . Creo que esta es la encapsulación más precisa de la información (a diferencia de help(Popen)
):
def __init__(self, args, bufsize=-1, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS,
shell=False, cwd=None, env=None, universal_newlines=False,
startupinfo=None, creationflags=0,
restore_signals=True, start_new_session=False,
pass_fds=(), *, encoding=None, errors=None):
Pero más informativa es la Popen
documentación :
subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *, encoding=None, errors=None)
Ejecute un programa hijo en un nuevo proceso. En POSIX, la clase usa un comportamiento similar a os.execvp () para ejecutar el programa secundario. En Windows, la clase usa la función Windows CreateProcess (). Los argumentos para Popen son los siguientes.
Comprender la documentación restante Popen
se dejará como un ejercicio para el lector.
shell=True
o (mejor aún) pasar el comando como una lista.
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
Utilizar:
import os
cmd = 'ls -al'
os.system(cmd)
os: este módulo proporciona una forma portátil de utilizar la funcionalidad dependiente del sistema operativo.
Para más os
funciones, aquí está la documentación.
Puede ser así de simple:
import os
cmd = "your command"
os.system(cmd)
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
Hay otra diferencia aquí que no se menciona anteriormente.
subprocess.Popen
ejecuta el <comando> como un subproceso. En mi caso, necesito ejecutar el archivo <a> que necesita comunicarse con otro programa, <b>.
Intenté el subproceso y la ejecución fue exitosa. Sin embargo, <b> no pudo comunicarse con <a>. Todo es normal cuando ejecuto ambos desde la terminal.
Uno más: (NOTA: kwrite se comporta de manera diferente a otras aplicaciones. Si intenta lo siguiente con Firefox, los resultados no serán los mismos).
Si lo intenta os.system("kwrite")
, el flujo del programa se congela hasta que el usuario cierre kwrite. Para superar eso intenté en su lugar os.system(konsole -e kwrite)
. Este programa de tiempo continuó fluyendo, pero kwrite se convirtió en el subproceso de la consola.
Cualquiera ejecuta kwrite sin ser un subproceso (es decir, en el monitor del sistema debe aparecer en el extremo izquierdo del árbol).
os.system
no le permite almacenar resultados, por lo que si desea almacenar los resultados en alguna lista o algo, subprocess.call
funciona.
Tiendo a usar el subproceso junto con shlex (para manejar el escape de cadenas entre comillas):
>>> import subprocess, shlex
>>> command = 'ls -l "/your/path/with spaces/"'
>>> call_params = shlex.split(command)
>>> print call_params
["ls", "-l", "/your/path/with spaces/"]
>>> subprocess.call(call_params)
Plug descarado, escribí una biblioteca para esto: P https://github.com/houqp/shell.py
Es básicamente un envoltorio para popen y shlex por ahora. También admite comandos de canalización para que pueda encadenar comandos más fácilmente en Python. Entonces puedes hacer cosas como:
ex('echo hello shell.py') | "awk '{print $2}'"
En Windows, puede importar el subprocess
módulo y ejecutar comandos externos llamando subprocess.Popen()
, subprocess.Popen().communicate()
y de la subprocess.Popen().wait()
siguiente manera:
# Python script to run a command line
import subprocess
def execute(cmd):
"""
Purpose : To execute a command and return exit status
Argument : cmd - command to execute
Return : exit_code
"""
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(result, error) = process.communicate()
rc = process.wait()
if rc != 0:
print "Error: failed to execute command:", cmd
print error
return result
# def
command = "tasklist | grep python"
print "This process detail: \n", execute(command)
Salida:
This process detail:
python.exe 604 RDP-Tcp#0 4 5,660 K
En Linux, en caso de que desee llamar a un comando externo que se ejecutará de forma independiente (seguirá ejecutándose después de que finalice el script de Python), puede usar una cola simple como cola de tareas o el comando at
Un ejemplo con la cola de tareas:
import os
os.system('ts <your-command>')
Notas sobre la cola de tareas ( ts
):
Puede establecer el número de procesos concurrentes que se ejecutarán ("ranuras") con:
ts -S <number-of-slots>
La instalación 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 mencionarlo batch
. Como en otros lugares, la os.system()
recomendación probablemente debería mencionar al menos que subprocess
es su reemplazo recomendado.
Puede usar Popen, y luego puede verificar el estado del procedimiento:
from subprocess import Popen
proc = Popen(['ls', '-l'])
if proc.poll() is None:
proc.kill()
Echa un vistazo al subproceso . Abrir .
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
os.popen()
en 2016. El script Awk podría reemplazarse fácilmente con el código nativo de Python.
echo $PATH
usandocall(["echo", "$PATH"])
, pero solo hizo eco de la cadena literal en$PATH
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.