Lenguajes de Programación

Configuración del intérprete interactivo de Python

El ejecutarse, el intérprete busca la variable de entorno PYTHONSTARTUP, y si está definida, ejecuta el fichero al que se refiere. Con ello, podemos preparar el intérprete para luego trabajar con él.

En .bashrc añadimos:

export PYTHONSTARTUP=~/.pythonstartup

para que en cada shell, el intérprete de python use el fichero de configuración.

Y ahora la configuración, por ejemplo:

import readline
import rlcompleter
import atexit
import os

#tab completion
readline.parse_and_bind(‘tab: complete’)
#history file
histfile = os.path.join(os.environ[‘HOME’],‘.pythonhistory’)
try:
        readline.read_history_file(histfile)
except IOError:
       pass
atexit.register(readline.write_history_file,histfile)
del os, histfile, readline, rlcompleter

Viene del libro Expert Python Programming, pág. 19, y lo que hace es añadir autocompletado con el tabulador, como en la shell, y un archivo histórico de los comandos ejecutados en el intérprete. El archivo se guardará en ~/.pythonhistory.

Python

Comments (0)

Permalink

(Des)activar el automount en Ubuntu 10.04

Tengo una memoria USB de la que quiero hacer un volcado en disco sin que se haga ninguna modificación sobre el original. Para ello, lo mejor es evitar que la unidad se monte automáticamente.

Gnome, desde hace ya unos cuantos años, por defecto monta las unidades que se añaden al sistema (CDs, memorias, discos externos, etc.): Cuando se inserta una memoria USB, el kernel detecta el nuevo dispositivo e informa a udev. Udev retransmite el mensaje mediante DBus. Mediante DBus se entera Gnome-VirtualFS (gvfs), que revisa su configuración y obra en consecuencia, montando la unidad.

kernel > udev > dbus > gvfs/nautilus

En versiones anteriores de Ubuntu esto era ligeramente diferente, ya que HALd estaba de por medio en lugar de udev.

El caso, es que si queremos que gnome no monte la unidad, lo que hay que hacer es cambiar la configuración del gvfs. Para ello, Gnome tiene un registro, a imagen y semejanza del de Windows. En tal registro hay una clave (/apps/nautilus/preferences/media_automount), de tipo bool, que por defecto está a true, indicando que sí se deben montar las unidades automáticamente.

¿Cómo se cambia el valor?

  • Mediante interfaz gráfica: se ejecuta el programa gconf-editor y encuentra uno la clave mediante el árbol de la derecha de la interfaz.
  • Mediante línea de comandos:
    • Con esto leemos el valor actual:
      gconftool –get /apps/nautilus/preferences/media_automount
    • y con esto:
      gconftool –type bool –set /apps/nautilus/preferences/media_automount false

      activamos o desactivamos el automount.

Y por automatizar, podemos añadir un alias a la configuración de la shell:

echo “alias automount=’gconftool –type bool –set /apps/nautilus/preferences/media_automount ‘”>> .bash_aliases

Por ejemplo:

$ automount false #Desactivar automount
$ automount true  #Reactivar el automontaje

Sources:

Shell scripting

Comments (0)

Permalink

Las variables volátiles

Son aquellas variables cuyo valor siempre que se lee, se lee de memoria, y siempre que se escribe, se escribe en memoria. Pasan el mínimo tiempo posible en los registros del microprocesador.
Al declararlas volátiles se le está indicando al compilador que no haga optimizaciones que eviten accesos a memoria para leerlas/escribirlas.

En un código como éste:

moehren+=7;
moehren*=2;

El compilador podría optimizar y generar código que:

  1. lee el valor de la variable de la pila (p.ej. x<-[moehren]) y lo guarda en un registro del micro
  2. suma 7 al registro (x+7)
  3. multiplica el registro por 2 ((x+7)*2)
  4. guarda el registro en la posición de la pila dedicada a la variable moehren ((x+7)*2->[moehren])

Hasta aquí todo en orden, el valor de mohren==(mohren+7)*2 y el número de accesos a memoria se minimiza, lo que (casi) siempre es de agradecer.

Y ahora vamos a suponer, que mientras una sentencia y otra, se recibe una interrupción y se ejecuta entre medias una sentencia:

moehren-=8;

El orden de ejecución sería como sigue:

  1. moehren+=7;
  2. moehren-=8;
  3. moehren*=2;

Con las optimizaciones del compilador esto queda:

  1. lee el valor de la variable (x<-[moehren]) de la pila y lo guarda en un registro del micro
  2. suma 7 al registro (x+7)
  3. salta a la ISR (rutina de servicio de la interrupción, que es, sencillamente, una función que se ejecutará en el medio)
  4. guarda los registros en la pila
  5. lee el valor de la variable de la pila (y<-[moehren]) y lo guarda en un registro del micro
  6. le resta 8 a ese registro (y-8)
  7. guarda ese registro en la posición de la pila dedicada a la variable moehren (y-8 -> [moehren])
  8. restaura los registros guardados en la pila y retorna a donde estaba antes de saltar a la ISR
  9. multiplica el registro por 2 ((x+7)*2)
  10. guarda el registro en la posición de la pila dedicada a la variable moehren ((x+7)*2->[moehren])

Es decir, que el valor de moehren==(moehren+7)*2, como si la ISR no se hubiera ejecutado.

Si por el contratio declaramos moehren como volatile:

volatile int moehren;

Cada vez que se lea/escriba esa variable, se accederá a memoria, lo cual es más lento, pero nos evita situaciones como la anterior.

El orden de ejecución del código generado en un caso similar al ejemplo anterior sería algo así:

  1. lee el valor de la variable (x<-[moehren]) de la pila a un registro
  2. suma 7 al registro (x+7)
  3. guarda el registro en la variable moehren (x+7 -> [moehren])
  4. salta a la ISR
  5. guarda los registros en la pila
  6. lee el valor de la variable (y<-[moehren], o sea y==x+7) de la pila a un registro
  7. le resta 8 a ese registro (y-8, que es lo mismo que x+7-8)
  8. guarda el registro en la variable moehren (y -> [moehren], o bien x+7-8 -> [moehren])
  9. restaura los registros guardados en la pila y retorna a donde estaba antes de saltar a la ISR
  10. lee el valor de la variable (z<-[moehren], z==x+7-8) de la pila a un registro
  11. multiplica el registro por 2 (z*2, (x+7-8)*2)
  12. guarda el registro en la variable moehren (z -> [moehren], o bien (x+7-8)*2 -> [moehren])

El valor que tiene ahora moehren==(moehren-1)*2. Ahora sí que se nota la ejecución de la ISR.

Ojo, porque con esto no se evita la necesidad de las primitivas de sincronización. Nada garantiza que dos procesos no accedan paralelamente y de forma no atómica a la variable en memoria. Si estamos trabajando en un entorno monotarea (un microcontrolador, normalmente), esto nos dará igual.

Lenguajes de Programación

Comments (0)

Permalink

Google Chrome… el cómic

Descubrí hace unas semanas que la gente de Google había publicado documentación acerca de su navegador Chrome… en forma de cómic.

El cómic se puede leer directamente por la web, o bien descargarse el PDF que he creado compilando todas las imágenes. Para crearlo, lo hice desde la línea de comandos con un poco de ayuda del paquete ImageMagick (para instalar en Debian o Ubuntu: sudo apt-get install imagemagick) y el wget.

Con esto nos descargamos cada una de las 39 páginas del cómic a un directorio:

mkdir gccomic
cd gccomic/
for i in {1..39}; do wget -O pagina`printf %02u $i`.jpg http://www.google.com/googlebooks/chrome/images/big/$i.jpg; done;

La expresión `printf %02u $i` sirve para que el número de página siempre tenga dos dígitos, siendo el primero de ellos 0 para números entre 0 y 9: pagina09.pdf, pagina10.pdf, etc. De esta forma, al ordenarlos alfabéticamente, los 10 ficheros con las respectivas 10 primeras páginas apareceran los primeros.

Y con esto juntamos todas las imágenes (en shell se encargará de que sea en orden alfabético) en un único PDF:

convert *.jpg Google\ Chrome\ Comic.pdf

A continuación, nos quedamos con el PDF resultante, lo difundimos bajo licencia Creative Commons Attribution-Noncommercial-No Derivative Works 2.5 License, y borramos todo el directorio gccomic/.

El cómic merece leerlo porque ilustra muy bien el funcionamiento de Chrome y la gran cantidad de ideas innovadoras que hay en ese navegador.

Pero además, opino que es un gran logro divulgativo presentar un producto y/o su documentación en forma de cómic, ya que simplifica enormemente su lectura y con ello acerca el producto al usuario final.Creo que puede ser un ejemplo a seguir para otros proyectos.

Shell scripting

Comments (0)

Permalink

Detectar ficheros duplicados con Python

Pensé que ya tenía una copia de The Little Book of Semaphores, pero por más que la buscaba no la encontraba.

Probablemente no la encontrara debido al enorme barullo que tengo en el directorio donde el aMule deposita todo lo que descarga y yo deposito todo lo que me bajo y quiero compartir.

Seguramente hubiera otro fichero con mismo contenido y distinto nombre. ¿Cómo encontrarlo?

Mediante md5sum *.pdf | sort podría revisar una por una cada entrada devuelta y buscar con un poco menos de dolor si hay algún duplicado, ya que sort ordena, pero que yo sepa no tiene una opción para mostrar sólo los duplicados (y en el manual no viene nada al respecto).

Quizá awk me ayudara, pero el caso es que hay que practicar Python (descargar fuente):

import sys
import hashlib

def do_hash(nombreFichero):
        fichero=open(nombreFichero,‘r’)
        contenido=fichero.read()
        fichero.close()
        return hashlib.md5(contenido).hexdigest()

if __name__==‘__main__’:
        hashes={}

        for fichero in sys.argv[1:]:
                clave = do_hash(fichero)
                try:
                        hashes[clave].append(fichero)
                except KeyError:
                        hashes[clave]=[fichero]

        for clave in hashes.keys():
                if len(hashes[clave])&gt;1:
                        print ‘Same key %s for:’%(clave)
                        for fichero in hashes[clave]:
                                print \t%s’%(fichero)

Funcionamiento:

Una vez comprobado que el script se está ejecutando (__name__ == ‘__main__’), y no ha sido llamado como módulo, por cada fichero en la línea de comandos averigua su hash mediante la función do_hash (que internamente usa MD5, pero podría usar SHA1 sin más que cambiarlo).
En un diccionario se guarda por cada hash, una lista con los nombres de los ficheros que tienen la misma hash.

Posteriormente, por cada hash encontrada, si en la lista de ficheros que tienen esa hash hay más de un fichero, se imprime cada nombre de fichero, de manera que el usuario puede visualizar qué ficheros tienen el mismo contenido:

pablo@golgi:~/Desktop$ python dups.py *.pdf
Same key 3f4568dc0b3e96b94f02c0b58d57b702 for:
        tls.2.pdf
        tls.pdf
pablo@golgi:~/Desktop$ rm tls.2.pdf

Probablemente, una salida de este estilo (agrupando los ficheros iguales sin verborrea):

pablo@golgi:~/Desktop$ python dups.py *.pdf
tls.2.pdf
tls.pdf

same1_1.pdf
same1_2.pdf
same1_3.pdf
pablo@golgi:~/Desktop$ rm tls.2.pdf  same1_2.pdf  same1_3.pdf

fuera más amigable para utilizar el comando desde algún script.

Ahí queda eso, por si a alguien (o a mí mismo en el futuro) le sirve para algo.

Ideas:

  • hacerlo en bash, o al menos de una manera más simple.
  • Si no es posible, programar una opción para ello en el sort.
  • Me gustaría ver qué tal funciona la función do_hash() con ficheros enormes (de 1G., p.e.). Esto habría que arreglarlo…

dups.py

Python

Comments (0)

Permalink