Ejecutando comandos desde Python

Anteriormente publiqué una introducción a Python, antes de continuar con el tutorial, dejo aquí un pequeño ejemplo de cómo se pueden realizar llamadas al shell desde Python. En concreto vamos a ver una llamada al comando ls:

#!/usr/bin/python
#-*- encoding:utf-8 -*-
#Es muy importante que la declaración de la codificación 
#de caracteres sea la primera línea antes del script.

#A.B: Comandos de sistema en Python:

#Importamos el módulo que contiene la función de llamada al sistema:
from subprocess import call

#La función call permite ejecutar el comando. Es necesario poner el
#flag de shell a True (segundo parámetro), en este caso hemos hecho
#una llamada al comando ls (con archivos ocultos) y lo hemos entubado
#en un 'more' para que pagine el resultado.
call("ls -la| more", shell=True)

Como se puede observar es bastante sencillo ejecutar comandos de shell desde Python. Para probarlo creamos un archivo nuevo "comando.py" que contenga el código anterior y lo guardamos. Luego tenemos que darle permisos de ejecución. Para no complicarnos un "chmod 777 comando.py" es suficiente. Y por último podemos ejecutarlo desde la línea de comandos con "./comando.py".


A veces los programas shell son un poco lentos en ejecución porque requieren del uso varios comandos y tuberías para realizar operaciones relativamente complejas. El comando "ls" que acabamos de ejecutar desde Python en bash podemos implementarlo directamente en Python. Probablemente los desarrollos de funcionalidades en Python sean más eficientes generalmente que los programas desarrollados en shell sobre todo en lo relacionado con manejo de ficheros, E/S, parseos de ficheros. Pues en shell script los programas se apoyan demasiado en concatenar la salida de unos comandos con otros mediante tuberías. En un ejemplo muy corto y sencillo vamos a ver cómo se ejecutaría el comando "ls" desde Python sin la ayuda del shell. Por simplicidad en el ejemplo evitamos la tubería con more:

#!/usr/bin/python
#-*- encoding:utf-8 -*-
#Es muy importante que la declaración de la codificación 
#de caracteres sea la primera línea antes del script.

#A.B: Implementación comando ls en Python

#Importamos el módulo "os" (http://docs.python.org/library/os.html) que
#permite operar con el sistema de ficheros
import os

#Obtenemos la lista de ficheros, os.getcwd() nos devuelve el directorio 
#actual y os.listdir(directorio) nos da la lista de ficheros del 
#directorio pasado como parámetro:
ficheros = os.listdir(os.getcwd())
 
#Por último, hacemos un bucle que recorre la lista de ficheros y los 
#imprimimos por pantalla: 
for f in ficheros:
 print f 
 


Eso es todo, queda en el tintero comprobar con comandos más avanzados el tiempo que tarda bash y el tiempo que tardaría Python en ejecutar la misma funcionalidad. En próximas entradas continuaré con el Tutorial de Python.
spacer

Tutorial de Python

Python es un lenguaje de moda, en la actualidad existen muchas de las ofertas de empleo que requieren conocimientos de Python, sobre todo en entidades que apuestan por el software libre y que, generalmente tienen sus aplicaciones web basadas en tecnología PHP. A rasgos generales, Python es parecido a PHP. 

Quiero aprovechar esta entrada y las próximas que escriba sobre Python para  recordar en el futuro lo que estoy aprendiendo, espero que también te sirva a tí que me lees. Y por favor, si me equivoco, corrígeme para que esto sea realmente útil.

Lo primero que debemos hacer es crear con un editor de textos o con un IDE que soporte Python un fichero que llamaremos "primer.py" que luego lanzaremos desde el intérprete de python.

Este es un ejemplo de script (módulo) en Python ("primer.py"):
#!/usr/bin/python
#-*- encoding:utf-8 -*-
#Es muy importante que la declaración de la codificación 
#de caracteres sea la primera línea antes del script.

#A.B: Probando Python

#Salida estandar
print "\nProbando la salida por estándar..."

#Creando variables de tipo primitivo
cadena = "Hola mundo"
entero = 5
real = 0.25
exponente = 1e-3
complejo = 2 + 3j

#Imprimiéndolas por pantalla
print "\n"
print "El tipo de cadena es" , type(cadena) , "y el valor es" , cadena
print "El tipo de entero es" , type(entero) , "y el valor es" , entero
print "El tipo de real es" , type(real) , "y el valor es" , real
print "El tipo de exponente es",type(exponente),"y el valor es",exponente
print "El tipo de complejo es",type(complejo),"y el valor es",complejo

#Los operadores son los típicos de todos los lenguajes. Destacar
#que se usa // para la división entera y / para la división real.
#Sin embargo, si usamos la división real con dos enteros, Python
#entiende que queremos que devuelva un entero. Es decir, que tanto
#3 // 2 como 3 / 2 devuelve 1. Para que la división sea real uno de
#los operandos debe ser real. Ej: 3 / 2.0 o bien, 3.0 / 2. 
#Otra opción es realizar un casting float(3)/2

print "\n"
print "Probando la división..."
print "3 / 2 = ", 3/2 
print "3 // 2 = ", 3//2
print "3.0 / 2 = ", 3.0 / 2 
print "float(3) / 2 = ", float(3) / 2
print "\n"

separador = "*"
#Multiplicamos el separador por 70 (Concatena 70 veces la cadena '*')
print separador * 70 

#Entrada por teclado
print "Probando la entrada por teclado. Pro favor escriba algo:"
entrada = raw_input()
print "\n"
print "Usted ha escrito: '" , entrada , "'" , "y el tipo es", type(entrada) 
print "\n"

#Vamos a definir una función
def miPrimeraFuncion(cad, val):
 """Esto saldrá en la ayuda con el comando help()"""
 print cad,val
 return "\nTerminado"

#Podemos no devolver nada, en ese caso Python devuelve None,
#que es parecido al null de Java. En Python no existen los 
#procedimientos.

#Llamamos a la función creada:
print "Llamada a la función con los parámetros cadena y complejo..."
print miPrimeraFuncion(cadena, complejo)

Para ejecutar el script debemos ir a una consola y escribir la sentencia: "python primer.py". La salida que genera este script es la siguiente:

antonio@i6253:~$ python primer.py

Probando la salida por estándar...

El tipo de cadena es <type 'str'> y el valor es Hola mundo
El tipo de entero es <type 'int'> y el valor es 5
El tipo de real es <type 'float'> y el valor es 0.25
El tipo de exponente es <type 'float'> y el valor es 0.001
El tipo de complejo es <type 'complex'> y el valor es (2+3j)

Probando la división...
3 / 2 =  1
3 // 2 =  1
3.0 / 2 =  1.5
float(3) / 2 =  1.5

**********************************************************************

Probando la entrada por teclado. Pro favor escriba algo:
Hola mundo!

Usted ha escrito: ' Hola mundo! ' y el tipo es <type 'str'>

Llamada a la función con los parámetros cadena y complejo...
Hola mundo (2+3j)

Terminado


Algunas observaciones generales e importantes son:
  • No existe símbolo para terminar la sentencia, es decir, una línea, una sentencia.
  • No hay que declarar los tipos de las variables.
  • La línea #-*- encoding: utf-8 -*- es necesaria para que python sepa cuál es la codificación de caracteres que debe tomar, en otro caso tendremos problemas con los acentos. Y debe estar en el comienzo del script.
  • El símbolo # sirve para comentarios de una sola línea.
  • Lo que escribimos entre """ y """ es un comentario de varias líneas .
  • El comentario que está debajo de la función que creamos es el que saldrá cuando pidamos la ayuda de la función. Sería algo así en el intérprete de Python: help(miPrimeraFuncion). Esto nos mostraría como ayuda lo que hemos puesto entre """ y """. 
En próximas entradas veremos un poco de orientación a objetos en Python y crearemos una clase, instanciaremos un objeto y llamaremos a sus métodos.
spacer

Multicast en Java (III) - Cliente Multicast

En la entrada anterior Multicast en Java (II) vimos un ejemplo de servidor multicast, vamos a ver ahora un cliente que sea capaz de "consumir" los datos que recibe del servidor. Recordemos el escenario: tenemos un servidor multicast que no es más que una aplicación que está enviando datos a través de una dirección de red de clase D  (multicast) por un puerto específico. 

Lo que vamos a hacer es crear un cliente que sea capaz de suscribirse a la dirección multicast en el puerto específico para recibir todo lo que emita el servidor. De forma que nuestro cliente siempre está "escuchando" al servidor multicast. Esto es útil en un entorno cliente-servidor en el que queremos que los clientes reciban los mismos datos, al mismo tiempo y de una vez, evitando enviarle datos a cada uno de los clientes.

Ejemplo de cliente

/**
* @author Antonio Bellido
*/
import java.io.*;
import java.net.*;

//Para probarlo, lanzar el MCServer y despues crear tantas 
//instancias de este como se quiera, espera a que haga el 
//join al grupo tarda unos segundos, y comienza a escribir 
//en la instancia del servidor (lo escrito saldrá en todos 
//estos clientes creados).

public class MCClient
{
public static void main (String [] args) throws IOException
{

//Creamos un socket multicast en el puerto 10000:
MulticastSocket s = new MulticastSocket (10000);

//Configuramos el grupo (IP) a la que nos conectaremos:
InetAddress group = InetAddress.getByName ("231.0.0.1");

//Nos unimos al grupo:
s.joinGroup (group);

//Leemos los paquetes enviados por el servidor multicast:
String salida = new String();
while(!salida.equals("salir"))
{

// Los paquetes enviados son de 256 bytes de maximo 
//(es adaptable)
byte [] buffer = new byte [256];

//Creamos el datagrama en el que recibiremos el paquete 
//del socket:
DatagramPacket dgp = new DatagramPacket (buffer, buffer.length);

// Recibimos el paquete del socket:
s.receive (dgp);

// Adaptamos la información al tamaño de lo que se envió 
//(por si se envió menos de 256):
byte [] buffer2 = new byte [dgp.getLength ()];

// Copiamos los datos en el nuevo array de tamaño adecuado:
System.arraycopy (dgp.getData (),
0,
buffer2,
0,
dgp.getLength ());

//Vemos los datos recibidos por pantalla:
salida = new String (buffer2);
System.out.println (salida);

}

//Salimos del grupo multicast
s.leaveGroup (group);

// Cerramos el socket:
s.close ();

}

}

spacer

Multicast en Java (II) - Servidor Multicast

En la entrada anterior Multicast en Java (I) vimos el esquema general de un servidor y un cliente multicast en JAVA. A continuación se muestra un ejemplo sencillo de servidor multicast y en la siguiente entrada mostraremos un ejemplo de cliente.

Podemos ejecutar ambos en cualquier intérprete de JAVA. El resultado será que todo lo que enviemos escribiendo por teclado desde el servidor será recibido en los clientes. El servidor seguirá enviando datos hasta que escribamos la palabra "salir". Podremos tener ejecutándose todos los clientes que queramos y todos recibirán los mismos datos que hemos escrito desde el servidor. Para probarlo podemos ejecutar una instancia del servidor desde Eclipse y todos los clientes que queramos.

Ejemplo de servidor 
**
* @author Antonio Bellido
*/
// MCServer.java
import java.io.*;
import java.net.*;
public class MCServer
{
public static void main (String[] args) throws IOException
{

System.out.println ("Arrancando el servidor multicast...\n");

//Creamos el MulticastSocket sin especificar puerto.
MulticastSocket s = new MulticastSocket ();

// Creamos el grupo multicast:
InetAddress group = InetAddress.getByName ("231.0.0.1");

// Creamos un datagrama vacío en principio:
byte [] vacio = new byte [0];
DatagramPacket dgp = new DatagramPacket(vacio, 0, group,
10000);

//Cogemos los datos a encapsular de la entrada 
//estándar (el teclado)
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String linea = br.readLine();

//El servidor enviará los datos que lea por teclado hasta que
//se escriba "salir":
while(!linea.equals("salir"))
{

//Creamos el buffer a enviar
byte [] buffer = linea.getBytes ();

//Pasamos los datos al datagrama
dgp.setData (buffer);

//Establecemos la longitud
dgp.setLength (buffer.length);

//Y por último enviamos:
s.send (dgp);

//Leemos de la entrada estandar para evitar bucles infinitos
linea = br.readLine();

}

// Cerramos el socket.
s.close ();
}
}


Continuar leyendo en Multicast en Java (III)
spacer

Multicast en Java (I)

El Multicast es un método de direccionamiento IP. Una dirección multicast está asociada con un grupo de receptores interesados. De acuerdo al RFC 3171 las direcciones desde la 224.0.0.0 a la 239.255.255.255 están destinadas para ser direcciones de multicast. Este rango se llama formalmente "Clase D". El emisor envía un único datagrama (desde la dirección unicast del emisor) a la dirección multicast y el router se encargará de hacer copias y enviarlas a todos los receptores que hayan informado de su interés por los datos de ese emisor.

Esquema general Multicast en Java
El esquema que sigue para el servidor y el cliente es el siguiente. En entradas posteriores dejaré un ejemplo de cada uno de ellos:

El Servidor:
//Creamos el MulticastSocket sin especificar puerto.
MulticastSocket s = new MulticastSocket ();

//Creamos el grupo multicast:
InetAddress group = InetAddress.getByName ("231.0.0.1");

// Creamos un datagrama vacío en principio:
byte [] vacio = new byte [0];

//Crear el Datagrama (mensaje, tamaño msj, grupo Multicast y puerto):
DatagramPacket dgp = new DatagramPacket (vacio, 0, group, 10000);

//Enviamos el paquete
s.send (dgp);


//Cerramos el socket:
s.close ();

El Cliente:
//Creamos un socket multicast en el puerto 10000:
MulticastSocket s = new MulticastSocket (10000);

//Configuramos el grupo (IP) a la que nos conectaremos:
InetAddress group = InetAddress.getByName ("231.0.0.1");

//Nos unimos al grupo:
s.joinGroup (group);

// Recibimos el paquete del socket:
DatagramPacket dgp = new DatagramPacket (buffer, buffer.length);
s.receive (dgp);

//Salimos del grupo multicast
s.leaveGroup (group);

// Cerramos el socket:
s.close (); 

Continuar leyendo en Multicast en Java (II)
spacer