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

Usar un servidor de nombres en OpenSolaris

Ayer tarde instalé OpenSolaris 2008.05 virtualizado sobre VMware Server en la Debian que uso habitualmente. El acceso a red lo configuré en VMware como NAT.

No hubo problemas que ahora mismo recuerde, excepto el uso de servidores DNS.

pablo@lynen:~$ ping 172.16.62.128

hacia mi ip (la averigüé con ifconfig -a) no hay problemas

172.16.62.128 is alive
pablo@lynen:~$ ping 172.16.62.1

hacia mi router (anfitrión/VMware) tampoco

172.16.62.1 is alive
pablo@lynen:~$ ping 172.16.62.2

hacia mi dirección para el anfitrión (VMware)

172.16.62.2 is alive
pablo@lynen:~$ ping 192.168.1.1

hacia el router de la LAN

192.168.1.1 is alive
pablo@lynen:~$ host google.es

Algo así como

no nameservers were reachable

Por defecto al instalar no había fichero

/etc/resolv.conf

, que en Solaris, al igual que en Linux, también sirve para definir qué servidor(es) de nombres se utilizarán. Creé uno:

pablo@lynen:~$ pfexec cat > /etc/resolv.conf
domain .
nameserver 192.168.10.1
nameserver 83.xx.xx.xx

El

pfexec

es como el

sudo

de Linux, más o menos, salvo que aquí nunca me pide mi password (supongo que será cuestión de la configuración por defecto).

Por lo demás se definen dos servidores de nombres: uno en mi red local (de la máquina anfitriona, sobre la que se está virtualizando), y otro en el exterior, en Internet.

Hasta aquí parecía resuelto:

pablo@lynen:~$ host google.es
google.es has address 66.249.93.104

[...]

Sin embargo al hacer

ping google.es

(p.ej.) no era capaz de resolver el nombre.

En Linux con añadir un

/etc/resolv.conf

correcto suele bastar, pero eso es porque la configuración por defecto de la mayoría de las distribuciones dice que al resolver un nombre de dominio, primero se debe mirar en el fichero

/etc/hosts

y luego ya resolver el nombre de dominio si ahí no se encuentra.

Esa configuración viene definida en

/etc/nsswitch.conf

(tanto en Linux como en OpenSolaris):

pablo@lynen:~$ cat /etc/nsswitch.conf
# CDDL HEADER START

[...]

group: files
hosts: files dns mdns
ipnodes: files dns mdns
networks: files

[...]

En esas dos líneas (

hosts

e

ipnodes

) originalmente sólo ponía “

hosts: files

” e “

ipnodes: files

“, por lo que tan sólo se buscaban en

/etc/hosts

las direcciones a resolver. Ahora se buscan primero ahí, y si no se encuentran se tratan de resolver por DNS, y si no lo consigue trata por último de usar mDNS.

No fue necesario en mi caso reiniciar ningún demonio ni nada más que modficiar esos dos ficheros. Con esos cambios pude navegar sin problemas desde Firefox y actualizar el IPS (

pkg refresh

).

OpenSolaris
Redes

Comments (0)

Permalink

Un cd mejorado

A menudo echaba en falta poder hacer

pablo@golgi:~$ cd dir1/dir2/

sin preocuparme de si

dir1/

y/o

dir2/

estaban creados, confiando en que

cd

los crearía.

Si bien se puede hacerle un hack al fuente de bash, es más laborioso que crear una función para la shell y añadirla a

.bashrc

:

ccd () {
if [ $# == 1 ]; then
if [ -d $1 ]; then
cd $1;
else
mkdir -p $1 && cd $1;
fi;
else
if [ $# == 0 ]; then
cd $HOME;
else
printf “Too many arguments\n”;
fi;
fi;
}

Por ejemplo:

pablo@golgi:~/md$ ccd d1/d2

(no existen ni d1/ ni d2/, así que los crea)

pablo@golgi:~/md/d1/d2$ cd ../..
pablo@golgi:~/md$ ccd d1/d2

(ya existen d1/ y d2/, así que no los crea)

pablo@golgi:~/md/d1/d2$ cd ../..
pablo@golgi:~/md$ ccd d1 d2
Too many arguments
pablo@golgi:~/md$ ccd
pablo@golgi:~$

Y ahora lo que hecho en falta es un plugin para wordpress que represente código adecuadamente.

Shell scripting

Comments (0)

Permalink

lastfm://

Si habéis usado alguna vez Last.FM y Firefox quizá os hayáis encontrado en la necesidad de conseguir que el navegador asocie el protocolo lastfm:// de las URIs con el reproductor de last.fm.

Para resolver este problema básicamente busqué en el google y encontré esta respuesta, que fusilo aquí mismo:

  1. Abrir una pestaña con la URL about:config
  2. Con el botón derecho del ratón (o el izquierdo, si somos zurdos :) haremos click para conseguir un menú contextual. Allí elegiremos la opción de Nuevo->Cadena
  3. Como nombre de la cadena pondremos network.protocol-handler.app.lastfm
  4. Como valor de la cadena usaremos /usr/bin/lastfm, o la ruta hacia el ejecutable de last.fm en nuestro ordenador (si no sabéis probad con which lastfm).

A partir de ahora todos los enlaces como este: lastfm://play/tracks/13258182 deberían funcionar, abriendo el reproductor de Last.FM y reproduciendo la canción desde allí.

lastfm

Comments (1)

Permalink