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])>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

History of Big- and Little-Endian

“The terms big-endian and little-endian derive from Jonathan Swift‘s 1726 satirical novel, Gulliver’s Travels. In the novel, the fictional Lilliputians‘ major political issue is whether eggs should be cracked open on the big end or the little end. Those who favor the big end are big-endians, whereas those who favor the small are little-endians.

The similarity between the Lilliputians and our big-endian versus little-endian debate is that the argument is rooted deeper in politics than technical merits.”

Procede del libro Linux Kernel Development, de Robert Love.
Capítulo 19: Portabilidad (2ª edición)

Update: Por cierto, se me olvidó poner esto de la misma fuente, está muy elegante (sirve para saber el endianness de la máquina donde se ejecuta):

int x=1;

if(1==*(char*)&x) {
        /* little endian */
}else{
        /* big endian */
}

Arquitectura de Computadores
Cultura

Comments (0)

Permalink

Blosc: agilizando el acceso a los datos en computación

En los últimos años se ha puesto de relieve que la velocidad a la que operan los microprocesadores crece mucho más rápido que la velocidad a la que se transfieren datos de la memoria al microprocesador.

Precisamente, para evitar esta asimetría Francesc Alted ha diseñado Blosc.

Blosc es un compresor optimizado para datos binarios. Comprime los datos con los que realizar computaciones, de manera que además de ocupar menos memoria, tardan menos tiempo en ser transferidos.

Con Blosc, por cada bloque de datos con el que trabajar, hay que transferir los datos, descomprimirlos, trabajar con ellos, comprimir los resultados y volver transferirlos.
Frente al proceso normal de transferir, computar y volver a transferir, consigue agilizar el tiempo empleado ya que en comprimir y descomprimir tarda muy poco frente a lo que se tarda en transferir los datos descomprimidos, precisamente por la enorme diferencia entre la velocidad de los micros y de las memorias.

Francesc presentará en el EuroSciPy 2009 este sistema, aplicándolo a las PyTables.

computación
Estructuras de datos

Comments (1)

Permalink

KeyKeriki: interceptando teclados inalámbricos

Desde hace algunos años venimos viendo una serie de periféricos, especialmente teclados y ratones, inalámbricos.

Primero fueron los que se comunicaban por infrarrojos, pero dadas las restricciones que tienen los infrarrojos en lo que a propagación se refiere empezamos a ver modelos que se comunicaban por radio.

En la actualidad se presentan, dentro de los que utilizan radiofrecuencia, dos familias: aquellos que trabajan en 27MHz., y aquellos que lo hacen en la banda de 2.4GHz.

KeyKeriki
Alguna gente de remote-exploit.org, hace cosa de año y medio empezaron a buscarle brechas de seguridad a algunos de estos dispositivos.

Fueron capaces de idear un circuito capaz de escuchar las comunicaciones de estos periféricos y estuvieron estudiando el protocolo de comunicaciones.

Para su sorpresa, gran parte de los mensajes que se transfieren del teclado al receptor van sin cifrar (mensajes de control), y los que sí van cifrados (mensajes con datos, como por ejemplo, qué tecla ha pulsado el usuario) utilizan un simple XOR con una clave que previamente se envió en claro (típico fallo de los algoritmos de clave simétrica).

Todas sus conclusiones acerca del protocolo de comunicaciones, y ciertas consideraciones sobre seguridad quedaron reflejadas en su paper: 27Mhz Wireless Keyboard Analysis Report. Así mismo, en ph-neutral 0x7d9 dieron una ponencia donde profundizaron en el funcionamiento de estos dispositivos.

Posteriormente han seguido trabajando en esa línea: han desarrollado un hardware (libre), y supuestamente también un software (libre, pero aún no disponible) que permite interceptar los teclados que estén al alcance del dispositivo.

Pareceser que aún es work in progress, pero la web del proyecto promete suficientes recursos para conseguir un cacharro de éstos totalmente operativo.

To Do
Aún quedan cabos sueltos en los que trabajar:

  • No trabajan aún con productos Logitech. Dicen en su página que el protocolo está estudiado, y que sólo les queda implementarlo, pero aún no hay una solución out-of-the-box para esta marca.
  • Se menciona en las transparencias que Microsoft utiliza una codificación ligeramente distinta (otros fabricantes usan codificación Miller), y no me queda claro ahora mismo si su dispositivo intercepta los periféricos de Microsoft o no.
  • Sólo han estudiado dispositivos de la banda de 27MHz. Queda otra banda por descubrir: la de 2.4GHz. Algunos de esta otra banda son los que funcionan mediante bluetooth, pero hay algún dispositivo que usa un protocolo no-tan-estándar en esa misma frecuencia. Me imagino que repetir el proyecto pero sobre 2.4GHz. puede complicarse: la electrónica a alta frecuencia debe ser más complicada, y quizá se utilicen modos de transmisión más elaborados (espectro extendido, p.ej.).

seguridad

Comments (0)

Permalink

Creando accesores en Python

Python tiene una característica que son las propiedades, pero al no conocerlas bien y ser particulares de este lenguaje, he creado una minúscula aplicación que genera el código para iniciar y acceder (get y set) a las propiedades de un objeto.

Esencialmente, es una función a la que le pasamos el nombre de las propiedades y su valor inicial, por ejemplo:

buildAccessor([
        (‘configfile’,\’/etc/foo.conf\’),
        ])

Y esto nos genera el código que debemos incluir en el constructor, así como los métodos get y set:

self.__configfile = ‘/etc/foo.conf’

        def getConfigfile(self):
                return self.__configfile

        def setConfigfile(self, value):
                self.__configfile=value

Con lo que si hacemos una prueba:

class objectFoo:
        def __init__(self):
                self.__configfile = ‘/etc/foo.conf’

        def getConfigfile(self):
                return self.__configfile

        def setConfigfile(self, value):
                self.__configfile=value

if __name__==‘__main__’:
        test=objectFoo()
        print(‘test.getConfigfile() says \’ + test.getConfigfile() + \’)
        test.setConfigfile(‘/home/linz/.foo’)
        print(‘Now, test.getConfigfile() says \’ + test.getConfigfile() + \’)

Resulta esto:

pablo@golgi:~/Desktop/py-pwgen$ python test_buildAccessor.py
test.getConfigfile() says ‘/etc/foo.conf’
Now test.getConfigfile() says ‘/home/linz/.foo’
pablo@golgi:~/Desktop/py-pwgen$

He decidido ponerle una página estática, por que puede ser que en el futuro amplíe el trabajo, o incluso que lo suba un SVN.

Output
Python

Comments (0)

Permalink