Desde python, como desde cualquier lenguaje de programación, podemos lanzar un comando externo al propio lenguaje de programación. Bien para cubrir algún aspecto que no provee el lenguaje o, la mayoría de las veces, para tapar nuestro desconocimiento del lenguaje.
En la mayoría de las ocasiones no es suficiente sólo con lanzar el comando. Queremos, además, poder procesar la salida recibida de alguna forma.
En python existen muchas formas de lanzar un comando externo, una de ellas es usando subprocess, que tiene algunas características particulares cuando el comando que lanzamos tiene pipes (tuberías).
En sistemas operativos entendemos por una tubería al procedimiento que permite enlazar la salida de un comando como entrada de otro:
In Unix-like computer operating systems (and, to some extent, Microsoft Windows), a pipeline is the original software pipeline: a set of processes chained by their standard streams, so that the output of each process (stdout) feeds directly as input (stdin) to the next one. Each connection is implemented by an anonymous pipe. Filter programs are often used in this configuration. Wikipedia
Un ejemplo sería, en un entorno linux, el siguiente comando que nos cuenta el número de ficheros y directorios que tenemos en un determinado directorio:
Curioso, ¿verdad?
Lo que hemos hecho ha sido ejecutar un ls -l (que muestra cada fichero y cada directorio en una línea) y el resultado, en vez de mostrarlo en pantalla como haría por defecto, se lo hemos pasado al comando wc -l que cuenta el número de lineas que ha recibido como entrada.
El ejemplo que queremos ver es el siguiente:
ipmitool es una herramienta que permite leer la información de los sensores de nuestro ordenador. Nuestro ordenador tiene una serie de sensores que nos informan del estado del sistema, la mayoría de ellos se refieren a la temperatura que hay en la CPU, en la tarjeta gráfica etc.
IPMItool is a utility for managing and configuring devices that support the Intelligent Platform Management Interface (IPMI) version 1.5 and version 2.0 specifications. IPMI is an open standard for monitoring, logging, recovery, inventory, and control of hardware that is implemented independent of the main CPU, BIOS, and OS.
Lo que hacemos con el comando anterior es mostrar la información de todos los sensores, y la salida, en vez de mostrarla en pantalla, la pasamos al comando grep que filtra sólo aquellas que tienen la palabra deg en algún lado: es decir el comando entero sólo muestra la información de aquellos sensores que tengan algo que ver con la temperatura (deg = grados )
La salida esperada sería algo como:
CPU 1 Temp | 50.000 | degrees C | ok | na | na | na | 93.000 | 95.000 | na
Ambient Temp0 | 39.000 | degrees C | ok | na | na | na | 70.000 | 75.000 | na
Ambient Temp1 | 47.000 | degrees C | ok | na | na | na | 70.000 | 75.000 | na
La primera columna es el nombre del sensor, la segunda la temperatura actual. Las tres últimas informan de las temperaturas máximas que el sistema soportará antes de enviar mensajes de warning, de peligro o críticos, respectivamente.
Si queremos procesar esa salida de forma “elegante” para poder realizar algunas operaciones con ellos (guardar histórico, enviar correos…) debemos guardar esos datos en, por ejemplo, un array.
Por extraño que pueda parecernos, python no deja lanzar un comando con un pipe porque entiende, con toda la razón, que son dos procesos que deben enlazarse de la forma correcta:
p1 = Popen(["ipmitool","sensor"], stdout=PIPE)
p2 = Popen(["grep", "deg"], stdin=p1.stdout, stdout = PIPE)
p1.stdout.close()
result = ( p2.communicate()[0] )
p1.wait()
Es de una lógica aplastante, pero no es nada intuitivo. Una vez que hemos adivinado eso, el resto es relativamente sencillo.
Conviene fijarse en con que gran habilidad hemos convertido la salida del proceso en líneas que luego son procesadas, a través del uso del readline y del split:
p1 = Popen(["ipmitool","sensor"], stdout=PIPE)
p2 = Popen(["grep", "deg"], stdin=p1.stdout, stdout = PIPE)
p1.stdout.close()
result = ( p2.communicate()[0] )
p1.wait()
result = result.splitlines ()
for data in result:
l = data.split ("|")
nombre = l[0].strip()
temperatura = l[1].strip()
twarn = l[7].strip()
tsoft = l[8].strip()
tcrit = l[9].strip()
La ausencia de vida social, lejos del dolor y la agonía que me auguraba mi psicólogo, permite encontrar breves momentos de paz en estas cosas.
Sad but true.
0 Vote