Comandos Popen de subprocesos y SO de Python

C

Introducción

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, popen3y 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, modey 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

(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

popenstdout
popen2stdin, stdout
popen3stdin, stdout, stderr
popen4stdin, stdout y stderr

Además, el popen2, popen3y 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:

$ 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!

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con tus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad