Introducción
Contenido
Python ofrece varias opciones para ejecutar procesos externos e interactuar con el sistema operativo. Sin embargo, los métodos son diferentes para Python 2 y 3. Python 2 tiene varios métodos en el os
módulo, que ahora están obsoletos y reemplazados por el subprocess
módulo, que es la opción preferida en Python 3.
A lo largo de este artículo, hablaremos de las diversas os
y subprocess
métodos, cómo usarlos, en qué se diferencian entre sí, en qué versión de Python deben usarse e incluso cómo convertir los comandos más antiguos a los más nuevos.
Con suerte, al final de este artículo comprenderá mejor cómo llamar a comandos externos desde el código Python y qué método debe utilizar para hacerlo.
Primero es el mayor os.popen*
métodos.
Los métodos os.popen *
los os
El módulo ofrece cuatro métodos diferentes que nos permiten interactuar con el sistema operativo (como lo haría con la línea de comandos) y crear un tubo a otros comandos. Estos métodos a los que me refiero son: popen
, popen2
, popen3
y popen4
, todos los cuales se describen en las siguientes secciones.
El objetivo de cada uno de estos métodos es poder llamar a otros programas desde su código Python. Esto podría ser llamar a otro ejecutable, como su propio programa C ++ compilado, o un comando de shell como ls
o mkdir
.
os.popen
los os.popen
El método abre una tubería desde un comando. Esta tubería permite que el comando envíe su salida a otro comando. La salida es un archivo abierto al que pueden acceder otros programas.
La sintaxis es la siguiente:
os.popen(command[, mode[, bufsize]])
Aquí el command
El parámetro es lo que ejecutará y su salida estará disponible a través de un archivo abierto. El argumento mode
define si este archivo de salida es legible (‘r’) o escribible (‘w’). Agregar una ‘b’ al mode
abrirá el archivo en modo binario. Así, por ejemplo, «rb» producirá un objeto de archivo binario legible.
Para recuperar el código de salida del comando ejecutado, debe utilizar el close()
método del objeto de archivo.
los bufsize
el parámetro dice popen
cuántos datos almacenar en búfer y puede asumir uno de los siguientes valores:
- 0 = sin búfer (valor predeterminado)
- 1 = línea almacenada en búfer
- N = tamaño aproximado del búfer, cuando N> 0; y valor predeterminado, cuando N <0
Este método está disponible para las plataformas Unix y Windows, y ha quedado obsoleto desde la versión 2.6 de Python. Si actualmente está utilizando este método y desea cambiar a la versión de Python 3, aquí está el equivalente subprocess
versión para Python 3:
Método reemplazado por
pipe = os.popen (‘cmd’, ‘r’, bufsize) | pipe = Popen (‘cmd’, shell = True, bufsize = bufsize, stdout = PIPE) .stdout |
pipe = os.popen (‘cmd’, ‘w’, bufsize) | pipe = Popen (‘cmd’, shell = True, bufsize = bufsize, stdin = PIPE) .stdin |
El siguiente código muestra un ejemplo de cómo utilizar el os.popen
método:
import os
p = os.popen('ls -la')
print(p.read())
El código anterior le pedirá al sistema operativo que enumere todos los archivos en el directorio actual. La salida de nuestro método, que se almacena en p
, es un archivo abierto, que se lee e imprime en la última línea del código. El resultado de este código (en el contexto de mi directorio actual) es el siguiente:
$ python popen_test.py
total 32
drwxr-xr-x 7 scott staff 238 Nov 9 09:13 .
drwxr-xr-x 29 scott staff 986 Nov 9 09:08 ..
-rw-r--r-- 1 scott staff 52 Nov 9 09:13 popen2_test.py
-rw-r--r-- 1 scott staff 55 Nov 9 09:14 popen3_test.py
-rw-r--r-- 1 scott staff 53 Nov 9 09:14 popen4_test.py
-rw-r--r-- 1 scott staff 49 Nov 9 09:13 popen_test.py
-rw-r--r-- 1 scott staff 0 Nov 9 09:13 subprocess_popen_test.py
os.popen2
Este método es muy similar al anterior. La principal diferencia es lo que produce el método. En este caso, devuelve dos objetos de archivo, uno para el stdin y otro archivo para el stdout.
La sintaxis es la siguiente:
popen2(cmd[, mode[, bufsize]])
Estos argumentos tienen el mismo significado que en el método anterior, os.popen
.
los popen2
El método está disponible para las plataformas Unix y Windows. Sin embargo, solo se encuentra en Python 2. Nuevamente, si desea utilizar el subprocess
en su lugar (que se muestra con más detalle a continuación), utilice lo siguiente en su lugar:
Método reemplazado por
(child_stdin, child_stdout) = os.popen2 (‘cmd’, modo, tamaño buf) | p = Popen (‘cmd’, shell = True, bufsize = bufsize, stdin = PIPE, stdout = PIPE, close_fds = True) (child_stdin, child_stdout) = (p.stdin, p.stdout) |
El siguiente código muestra un ejemplo de cómo utilizar este método:
import os
in, out = os.popen2('ls -la')
print(out.read())
Este código producirá los mismos resultados que se muestran en el primer resultado del código anterior. La diferencia aquí es que la salida del popen2
El método consta de dos archivos. Por lo tanto, la segunda línea de código define dos variables: in
y out
. En la última línea, leemos el archivo de salida. out
e imprimirlo en la consola.
os.popen3
Este método es muy similar a los anteriores. Sin embargo, la diferencia es que la salida del comando es un conjunto de tres archivos: stdin, stdout y stderr.
La sintaxis es:
os.popen3(cmd[, mode[, bufsize]])
donde los argumentos cmd
, mode
y bufsize
tienen las mismas especificaciones que en los métodos anteriores. El método está disponible para plataformas Unix y Windows.
Tenga en cuenta que este método ha quedado obsoleto y la documentación de Python nos aconseja reemplazar el popen3
método de la siguiente manera:
Método reemplazado por
Te puede interesar:Travesía de árbol de preorden modificada en Django(niño_stdin, child_stdout, child_stderr) = os.popen3 (‘cmd’, modo, tamaño buf) |
p = Popen (‘cmd’, shell = True, bufsize = bufsize, stdin = PIPE, stdout = PIPE, stderr = PIPE, close_fds = True) (niño_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr) |
Como en los ejemplos anteriores, el código siguiente producirá el mismo resultado que se ve en nuestro primer ejemplo.
import os
in, out, err = os.popen3('ls -la')
print(out.read())
Sin embargo, en este caso, tenemos que definir tres archivos: stdin, stdout y stderr. La lista de archivos de nuestro ls -la
El comando se guarda en el out
archivo.
os.popen4
Como probablemente adivinó, el os.popen4
El método es similar a los métodos anteriores. Sin embargo, en este caso, solo devuelve dos archivos, uno para stdin y otro para stdout y stderr.
Este método está disponible para las plataformas Unix y Windows y (¡sorpresa!) También ha quedado obsoleto desde la versión 2.6. Para reemplazarlo con el correspondiente subprocess
Popen
llamar, haga lo siguiente:
Método reemplazado por
(child_stdin, child_stdout_and_stderr) = os.popen4 (‘cmd’, modo, tamaño buf) | p = Popen (‘cmd’, shell = True, bufsize = bufsize, stdin = PIPE, stdout = PIPE, stderr = STDOUT, close_fds = True) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) |
El siguiente código producirá el mismo resultado que en los ejemplos anteriores, que se muestra en el primer resultado del código anterior.
import os
in, out = os.popen4('ls -la')
print(we.read())
Como podemos ver en el código anterior, el método es muy similar a popen2
. sin embargo, el out
archivo en el programa mostrará los resultados combinados de las secuencias stdout y stderr.
Resumen de diferencias
Las diferencias entre los diferentes popen*
Todos los comandos tienen que ver con su salida, que se resume en la siguiente tabla:
Argumentos del método
Te puede interesar:Descargar archivos con Pythonpopen | stdout |
popen2 | stdin, stdout |
popen3 | stdin, stdout, stderr |
popen4 | stdin, stdout y stderr |
Además, el popen2
, popen3
y popen4
solo están disponibles en Python 2 pero no en Python 3. Python 3 tiene disponible el popen
método, pero se recomienda utilizar el subprocess
en su lugar, que describiremos con más detalle en la siguiente sección.
El método susbprocess.Popen
los módulo de subproceso fue creado con la intención de reemplazar varios métodos disponibles en el os
módulo, que no se consideraron muy eficientes. Dentro de este módulo, encontramos el nuevo Popen
clase.
La documentación de Python recomienda el uso de Popen
en casos avanzados, cuando otros métodos como subprocess.call
no puede satisfacer nuestras necesidades. Este método permite la ejecución de un programa como un proceso hijo. Debido a que esto lo ejecuta el sistema operativo como un proceso separado, los resultados dependen de la plataforma.
Los parámetros disponibles son los siguientes:
subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
Una diferencia principal de Popen
es que es una clase y no solo un método. Por lo tanto, cuando llamamos subprocess.Popen
, en realidad estamos llamando al constructor de la clase Popen
.
Hay bastantes argumentos en el constructor. Lo más importante de entender es args
, que contiene el comando para el proceso que queremos ejecutar. Puede especificarse como una secuencia de parámetros (a través de una matriz) o como una sola cadena de comando.
El segundo argumento que es importante comprender es shell
, que por defecto es False
. En Unix, cuando necesitamos ejecutar un comando que pertenece al shell, como ls -la
, tenemos que configurar shell=True
.
Por ejemplo, el siguiente código llamará al comando Unix ls -la
a través de un caparazón.
import subprocess
subprocess.Popen('ls -la', shell=True)
Los resultados se pueden ver en el resultado a continuación:
Te puede interesar:Listas vinculadas de Python$ python subprocess_popen_test.py
total 40
drwxr-xr-x 7 scott staff 238 Nov 9 09:13 .
drwxr-xr-x 29 scott staff 986 Nov 9 09:08 ..
-rw-r--r-- 1 scott staff 52 Nov 9 09:13 popen2_test.py
-rw-r--r-- 1 scott staff 55 Nov 9 09:14 popen3_test.py
-rw-r--r-- 1 scott staff 53 Nov 9 09:14 popen4_test.py
-rw-r--r-- 1 scott staff 49 Nov 9 09:13 popen_test.py
-rw-r--r-- 1 scott staff 56 Nov 9 09:16 subprocess_popen_test.py
Usando el siguiente ejemplo de una máquina con Windows, podemos ver las diferencias de usar el shell
parámetro más fácilmente. Aquí estamos abriendo Microsoft Excel desde el shell o como un programa ejecutable. Desde el shell, es como si abriéramos Excel desde una ventana de comandos.
El siguiente código abrirá Excel desde el shell (tenga en cuenta que tenemos que especificar shell=True
):
import subprocess
subprocess.Popen("start excel", shell=True)
Sin embargo, podemos obtener los mismos resultados llamando al ejecutable de Excel. En este caso no estamos usando el shell, así que lo dejamos con su valor predeterminado (False
); pero tenemos que especificar la ruta completa al ejecutable.
import subprocess
subprocess.Popen("C:Program Files (x86)Microsoft OfficeOffice15excel.exe")
Además, cuando instanciamos el Popen
class, tenemos acceso a varios métodos útiles:
Descripción del método
Popen.poll() |
Comprueba si el proceso hijo ha terminado. |
Popen.wait() |
Espere a que termine el proceso secundario. |
Popen.communicate() |
Permite interactuar con el proceso. |
Popen.send_signal() |
Envía una señal al proceso hijo. |
Popen.terminate() |
Detiene el proceso hijo. |
Popen.kill() |
Mata a un proceso infantil. |
La lista completa se puede encontrar en el documentación del subproceso. El método más utilizado aquí es communicate
.
los communicate
El método nos permite leer datos de la entrada estándar y también nos permite enviar datos a la salida estándar. Devuelve una tupla definida como (stdoutdata, stderrdata)
.
Por ejemplo, el siguiente código combinará Windows dir
y sort
comandos.
import subprocess
p1 = subprocess.Popen('dir', shell=True, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p2 = subprocess.Popen('sort /R', shell=True, stdin=p1.stdout)
p1.stdout.close()
out, err = p2.communicate()
Para combinar ambos comandos, creamos dos subprocesos, uno para el dir
comando y otro para el sort
mando. Como queremos ordenar en orden inverso, agregamos /R
opción a la sort
llamada.
Definimos la salida estándar del proceso 1 como PIPE, lo que nos permite usar la salida del proceso 1 como entrada para el proceso 2. Luego, debemos cerrar la salida estándar del proceso 1, para que pueda ser utilizada como entrada por el proceso 2. El La comunicación entre procesos se logra a través del communicate
método.
Ejecutar esto desde un shell de comandos de Windows produce lo siguiente:
> python subprocess_pipe_test.py
11/09/2017 08:52 PM 234 subprocess_pipe_test.py
11/09/2017 07:13 PM 99 subprocess_pipe_test2.py
11/09/2017 07:08 PM 66 subprocess_pipe_test3.py
11/09/2017 07:01 PM 56 subprocess_pipe_test4.py
11/09/2017 06:48 PM <DIR> ..
11/09/2017 06:48 PM <DIR> .
Volume Serial Number is 2E4E-56A3
Volume in drive D is ECA
Directory of D:MyPopen
4 File(s) 455 bytes
2 Dir(s) 18,634,326,016 bytes free
Terminando
los os
Los métodos presentaban una buena opción en el pasado, sin embargo, en la actualidad subprocess
El módulo tiene varios métodos que son más potentes y eficientes de usar. Entre las herramientas disponibles se encuentra Popen
class, que se puede utilizar en casos más complejos. Esta clase también contiene el communicate
, que nos ayuda a unir diferentes comandos para una funcionalidad más compleja.
¿Qué usas el popen*
métodos para, y cuál prefiere? ¡Háznoslo saber en los comentarios!