¿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?
4886
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"])
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.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 = Truefor
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ándoshell=False
, luego useshlex.split
para una manera fácil de hacerlo docs.python.org/2/library/shlex.html#shlex.splitAquí 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: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 delsubprocess
módulo. Esto pretende ser un reemplazoos.popen
pero tiene la desventaja de ser un poco más complicado en virtud de ser tan completo. Por ejemplo, dirías:en vez de:
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 delsubprocess
módulo. Esto es básicamente como laPopen
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: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 unCompletedProcess
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:
e imagine que el usuario ingresa algo "mi mamá no me amaba && rm -rf /" que podría borrar todo el sistema de archivos.
fuente
open
.subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.runsubprocess.run(..)
, ¿qué hace exactamente ? Esto no captura stdout o stderr de manera predeterminada. ¿implicar? ¿Qué pasa consubprocess.check_output(..)
STDERR?echo
frente de la cadena pasada aPopen
? Entonces el comando completo seráecho my mama didnt love me && rm -rf /
.subprocess.run()
o sus hermanos mayoressubprocess.check_call()
et al. Para los casos en que estos no son suficientes, veasubprocess.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:
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=
ystderr=
) y se comportará comoos.system()
.fuente
.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: nos
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 innecesariamenteshell=True
. Prueba una de lassubprocess.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:
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:
/ * 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:
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.
fuente
DETACHED_PROCESS
decreationflags
evita esto evitando que el niño herede o la creación de una consola. Si, en cambio, desea una nueva consola, useCREATE_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.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.
fuente
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.
fuente
subprocess
cuándoshell=False
, luego useshlex.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 )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.fuente
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.Esperemos que esto te ayude a tomar una decisión sobre qué biblioteca usar :)
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.
os se usa para "funcionalidad dependiente del sistema operativo". También se puede usar para llamar a comandos externos con
os.system
yos.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 usarlosubprocess.run
.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.
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.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.
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)
enviado se conoce como "subproceso para los humanos". Se utiliza como una envoltura conveniente alrededor del
subprocess
módulo.commands
contiene funciones de contenedor paraos.popen
, pero se ha eliminado de Python 3 ya quesubprocess
es una mejor alternativa.La edición se basó en el comentario de JF Sebastian.
fuente
Siempre uso
fabric
para esto cosas como:Pero esta parece ser una buena herramienta:
sh
(interfaz de subproceso de Python) .Mira un ejemplo:
fuente
Compruebe también la biblioteca Python "pexpect".
Permite el control interactivo de programas / comandos externos, incluso ssh, ftp, telnet, etc. Puede escribir algo como:
fuente
Con la biblioteca estándar
Use el módulo de subproceso (Python 3):
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 otrassubprocess
funciones en caso de que no quiera (o no pueda) proporcionarlas en forma de listas:Con dependencias externas
Si no le importan las dependencias externas, use plumbum :
Es el mejor
subprocess
envoltorio. Es multiplataforma, es decir, funciona tanto en sistemas Windows como Unix. Instalar porpip install plumbum
.Otra biblioteca popular es sh :
Sin embargo,
sh
dejó de admitir Windows, por lo que ya no es tan impresionante como solía ser. Instalar porpip install sh
.fuente
Si necesita la salida del comando que está llamando, puede usar subprocess.check_output (Python 2.7+).
También tenga en cuenta el parámetro de shell .
fuente
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 essubprocess.check_output("ls -l /dev/null".split())
.Así es como ejecuto mis comandos. Este código tiene todo lo que necesitas prácticamente
fuente
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 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:
Elevar en ejecución fallida:
Salida de captura:
Respuesta original:
Recomiendo probar Envoy . Es un contenedor para subprocesos, que a su vez tiene como objetivo reemplazar los módulos y funciones más antiguos. El enviado es un subproceso para los humanos.
Ejemplo de uso de README :
Tubería cosas alrededor también:
fuente
Usar subproceso .
... o para un comando muy simple:
fuente
os.system
está bien, pero un poco anticuado. Tampoco es muy seguro. En cambio, inténtalosubprocess
.subprocess
no llama a sh directamente y, por lo tanto, es más seguro queos.system
.Obtenga más información aquí .
fuente
subprocess
no elimina todos los problemas de seguridad y tiene algunos problemas molestos.Simple, use
subprocess.run
, que devuelve unCompletedProcess
objeto:¿Por qué?
A partir de Python 3.5, la documentación recomienda subprocess.run :
Aquí hay un ejemplo del uso más simple posible, y hace exactamente lo que se le pide:
run
espera a que el comando finalice correctamente y luego devuelve unCompletedProcess
objeto. En su lugar, puede aumentarTimeoutExpired
(si le da untimeout=
argumento) oCalledProcessError
(si falla y pasacheck=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:
Captura de salida
Si desea capturar la salida, puede pasar
subprocess.PIPE
a la correspondientestderr
ostdout
:(Me parece interesante y ligeramente contradictorio que la información de la versión se ponga en stderr en lugar de stdout).
Pase una lista de comandos
Uno podría pasar fácilmente de proporcionar manualmente una cadena de comando (como sugiere la pregunta) a proporcionar una cadena construida programáticamente. No construya cadenas mediante programación. Este es un posible problema de seguridad. Es mejor asumir que no confía en la entrada.
Nota solo
args
debe pasarse posicionalmente.Firma completa
Aquí está la firma real en la fuente y como lo muestra
help(run)
:Los
popenargs
ykwargs
son dados alPopen
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=
ycheck=True
mejor de lo que podría:y este ejemplo
check=True
es mejor que uno que se me ocurra:Firma ampliada
Aquí hay una firma expandida, como se indica en la documentación:
Tenga en cuenta que esto indica que solo la lista de argumentos debe pasarse posicionalmente. Entonces pase los argumentos restantes como argumentos de palabras clave.
Popen
Cuando uso
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 dehelp(Popen)
):Pero más informativa es la
Popen
documentación :Comprender la documentación restante
Popen
se dejará como un ejercicio para el lector.fuente
shell=True
o (mejor aún) pasar el comando como una lista.También hay Plumbum
fuente
Utilizar:
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.fuente
Puede ser así de simple:
fuente
os.system
explícitamente recomienda evitarlo a favor desubprocess
.Me gusta bastante shell_command por su simplicidad. Está construido sobre el módulo de subproceso.
Aquí hay un ejemplo de la documentación:
fuente
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 lugaros.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).
fuente
os.system
no le permite almacenar resultados, por lo que si desea almacenar los resultados en alguna lista o algo,subprocess.call
funciona.fuente
subprocess.check_call
Es conveniente si no desea probar los valores de retorno. Lanza una excepción en cualquier error.fuente
Tiendo a usar el subproceso junto con shlex (para manejar el escape de cadenas entre comillas):
fuente
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:
fuente
En Windows, puede importar el
subprocess
módulo y ejecutar comandos externos llamandosubprocess.Popen()
,subprocess.Popen().communicate()
y de lasubprocess.Popen().wait()
siguiente manera:Salida:
fuente
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:
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 simplemake
, agregarlo a su ruta y listo.fuente
ts
no es estándar en ninguna distribución que conozco, aunque el puntero aat
es ligeramente útil. Probablemente también deberías mencionarlobatch
. Como en otros lugares, laos.system()
recomendación probablemente debería mencionar al menos quesubprocess
es su reemplazo recomendado.Puede usar Popen, y luego puede verificar el estado del procedimiento:
Echa un vistazo al subproceso . Abrir .
fuente
Para obtener la identificación de red de OpenStack Neutron :
Salida de nova net-list
Salida de impresión (networkId)
fuente
os.popen()
en 2016. El script Awk podría reemplazarse fácilmente con el código nativo de Python.