Cómo buscar y borrar archivos de forma recursiva en Linux

¡Hola inventores! Como administradores de sistemas o incluso como usuarios comunes de sistemas Gnu/Linux, les puede haber pasado que necesitáramos encontrar el mismo archivo repetido en múltiples directorios o carpetas, o tal vez borrar todos los archivos de un tipo específico, por lo que tendríamos que ir carpeta a carpeta borrando cada uno, pero ¡Eso se acabó! Hoy vamos a ver una manera de ahorrarnos todo este trabajo con un solo comando. ¡Vamos allá!

Por cierto, si quieres ver la versión en video de este micro Tip, te lo dejo en mi canal de youtube.

PASO 1 – Entrar en el directorio

Primero, debemos situarnos en el directorio en el que queremos buscar usando el comando cd:

cd directorio_objetivo

PASO 2 – Listar antes de borrar Por tipo

Acto seguido, podemos listar los archivos con el comando find, sí, con el comando find, sin usarl ls. Esto lo haremos para saber qué estaremos borrando antes de borrar, en caso de que sean muchos archvios; ya que lo hará de manera recursiva, es muy recomendable.

find . -name "*.png" -type f

El punto «.» indica que tiene que buscar a partir del directorio en el que nos encontramos en ese momento y, con el ‘*.png‘ le decimos que busque todos los archivos con extensión .png.

PASO 3 – Buscar y borrar

En el paso anterior hemos listado los archivos, pero ahora, para borrarlos, añadiremos el parámetro -delete  al final del comando:

find . -name "*.png" -type f -delete

Con esto, habremos eliminado con un sólo comando todos los archivos que deseabamos borrar sin tener que ir navegando por todas las carpetas para eliminar uno a uno.

Buscar y borrar por palabra clave

Otra cosa que puedo hacer es buscar una palabra clave del nombre del archivo que quisieramos encontar:

find . -name "*palabra_clave*" -type f -delete

Con esto, habremos eliminado con un sólo comando todos los archivos que contengan palabra_clave en su nombre de manera recursiva.

¿Cómo hacer que reconozca mayúsculas y minúsclas?

Agregando -iname en lugar de -name al comando, podemos hacer que tanto palabra_clave como PALABRA_CLAVE se incluyan en la busqueda, lo mismo para .png o .PNG:

find . -iname "*pAlAbrA_clAvE*" -type f -delete

Muy Bien , espero que les haya servido, ¡Y hasta un próximo micro tip!

¿Cómo unir dos diccionarios en python? (ACTUALIZADO)

Hola de nuevo.

Como siempre acá les dejo otro microtip, que les puede servir en algún momento y esta vez es de python…

Antes de comenzar, si prefieres ver esta explicación en video, te lo dejo por acá

Si prefieres seguir leyedo, ¡Comencemos!

Python 3 nos trae nuevas funcionalidades interesantes que nos hacen la vida as facil y una de ellas es este interesante trudo que en python 2.7 no podíamos hacer directamente. Los siguientes pasos son válidos desde la versión 3.5 de Python, por lo que te servirá siempre que tengas una versión ygual o mayor a esta.

Bien, supongamos que tenemos dos dict «X» y «Y» y queremos hacer un «merge» de estos, lo único que deberíamos hacer es lo siguiente:


>>> x = {'a':1,'b':2}
>>> y = {'b':3,'c':4}
>>> z = {**x, **y}
>>> z
{'b': 3, 'c': 4, 'a': 1}

¿Facil, no? Python ❤

Espero que les sea de utilidad.

Hasta un próximo microtip.

¿Cómo encontrar los dispositivos montados en MTP en Linux?

Buen día, tarde, noche o lo que sea cuando leas este post.
Este va a ser un microtip sobre algo que parece trivial, pero que puede pasarnos y bueno, para eso llegate aquí ¿Correcto? Pues a lo que vamos.

Cuando conectas un teléfono, por ejemplo con una SD Card, Nautilus la monta automáticamente por nosotros y la deja lista para usar, pero si la buscamos en el directorio /media/nuestro_usuario/ nunca vemos nada, por lo que para hacer cosas por terminal no nos sirve mucho.

Si intentas buscar el punto de montaje, podrás verlo en nautilus en forma de tooltip o pulsando Ctrl+l pero en cualquier caso, te mostrará algo como esto:

mtp://[usb:003,014]/sdcard1/directorio/directorio

Esto es porque «mtp://[usb:003,014]» es la referencia al punto de montaje que usa nautilus para este dispositivo… Ahora ¿Donde está eso?.

Pues para encontrarlo vamos a:

/run/user/1000/gvfs/mtp\:host\=%5Busb%3A003%2C014%5D/sdcard1/directorio/directorio

El directorio /1000/  puede cambiar dependiendo de la cantidad de dispositivos de este tipo tengas conectados(como por ejemplo, la memoria interna del teléfono).

Lo iportante aquí es la ruta /run/user/ lo que sea /gvfs/mtp\:host\=  ya que de aquí en adelante será el directorio y dispositivo que busques…

Bueno, es todo por este micho tip. Espero que les sea de utilidad.

May the force be with you!

 

Iteradores y Generadores

Este articulo  como varios de los que verán está enfocado al lenguaje de programación Python, pero tiene los conceptos generales que de bemos tener sobre iteradores para otros lenguajes. Así que hoy resolveremos preguntas como ¿Qué es un iterador? ¿Qué es un iterable? ¿Para qué se usan los iteradores? ¿Cómo usarlos? ¿Cual es la diferencia entre in iterador y un iterable? ¿Diferencia entre un iterador y un generador?

¿Qué es un iterador?

En resumidas cuentas, «Un iterador básicamente es un objeto que permite recorrer uno a uno los elementos almacenados en una estructura de datos, y operar con ellos». Un iterador muchas veces es llamado “cursor”, especialmente dentro del contexto de una base de datos.

En este sentio, un objeto tipo iterator es un objeto que representa un flujo de datos, el cual puede ser recorrido en un proceso iterativo, como un bucle for, dentro de una función map o filter, en la creación de una list comprehension o generador(que explicaremos luego), o en una comparación in.

Todo objeto iterator contiene implementado un método __next__() que es llamado en cada iteración devolviendo los sucesivos elementos del flujo de datos cada vez. El flujo de datos del objeto no tiene por qué estar guardado en memoria, sino que puede ser generado en tiempo real en cada iteración.

El objeto iterator guarda un estado interno para saber cuál fue el último elemento obtenido. Así, en la siguiente llamada al método __next__(), se obtendrá el siguiente elemento correcto. Cuando ya no quedan más elementos en el flujo de datos del iterator, la función __next__() lanza StopIteration. El estado interno no se reinicia automáticamente al llegar al final del flujo o al empezar a recorrerlo de nuevo. Es decir, sólo se puede recorrer una vez.

Además, tiene implementado el método __iter__() que devuelve el propio objeto iterator. Esto es necesario para poder implementar bucles con objetos iterator, como explicaremos después.

Así que.. ¿Qué es un iterable?

Es un tipo de objeto que devuelve sus elementos de uno en uno cada vez. Tiene implementado alguno de estos dos métodos:

  • __iter__() que devuelve un objeto iterator a partir de este objeto iterable.
  • __getitem__() que accede a cada uno de los elementos para índices empezando desde 0.

Un objeto iterable no tiene por qué tener definido el método __next__(), En cambio, al tener la obligación de implementar el método __iter__() o __getitem__(), puede ser utilizado como argumento para la función iter() y así recorrer el iterator resultante.

Ahora bien,

En Python existen diferentes estructuras de datos que pueden ser recorridas secuencialmente mediante el uso de bucles. Estos objetos llamados iteradores, básicamente, son secuencias, contenedores y ficheros de texto. Los «Contenedores» son objetos que tienen definidos el método __getitem__() (además de __setitem__() o __delitem__() si el contenedor es mutable) para acceder a los elementos del contenedor. Dependiendo que el contenedor sea una secuencia o un mapeador (mapping), el valor pasado por argumento a __getitem__() puede ser un índice o un objeto slicing para el primero, o una clave única para el segundo.

La función __getitem__() se ejecuta implícitamente al usar el operador [] con el valor argumento de acceso entre corchetes.

Las listas y tuplas son contenedores secuencia que además son iterables al tener implementado el método __iter__() y el método __getitem__() (para índices empezando desde 0). Pero en cambio no son iterator porque no contienen el método __next__(). Tanto Iterable como Iterator son clases abstractas definidas dentro del módulo collections las cuales contienen los métodos abstractos __iter__() o __next__(). Por lo tanto, una instancia de una clase heredada de Iterable debe implementar el método __iter__() (haciendo que cumpla una de las condiciones anteriores para iterables); y una instancia de una clase heredada de Iterator debe implementar los métodos __iter__() y __next__() cumpliendo las condiciones de iterator explicadas anteriormente.

En particular, en Python, los iteradores tienen que implementar un método next que debe devolver los elementos, de a uno por vez, comenzando por el primero. Y al llegar al final de la estructura, debe levantar una excepción de tipo StopIteration.

Es decir que las siguientes estructuras son equivalentes:

 
for elemento in secuencia:
    # hacer algo con elemento
 
iterador = iter(secuencia)
while True:
    try:
        elemento = iterador.next()
    except StopIteration:
        break
    # hacer algo con elemento

La declaración for/in se utiliza con frecuencia para recorrer los elementos de distintos tipos de iteradores: los caracteres de una cadena, los elementos de una lista o una tupla, las claves y/o valores de un diccionario e incluso las líneas de un archivo:

# Recorrer los caracteres de una cadena:

cadena = "Python"
for caracter in cadena:
    print(caracter)

# Recorrer caracteres de cadena anterior, en sentido inverso.
    
for caracter in cadena[::-1]:
    print(caracter)

# Recorrer los elementos de una lista

lista = ['una', 'lista', 'es', 'un', 'iterable']
for palabra in lista:
    print(palabra)
    
# Recorrer los elementos de la lista anterior, al revés

for palabra in lista[::-1]:
    print(palabra)

# Obtener índice para recorrer todos los elementos de la lista

for indice in range(len(lista)):
    print (indice, lista[indice])

# Recorrer las claves de un diccionario

artistas = { 'Lorca' : 'Escritor', 'Goya' : 'Pintor'}
for clave, valor in artistas.items():
    print(clave,':',valor)
    
# Leer las líneas de un archivo de texto, una a una

for linea in open("datos.txt"):
    print(linea.rstrip())

La función iter()

La función iter() se suele emplear para mostrar cómo funciona en realidad un bucle implementado con for/in. Antes del inicio del bucle la función iter() retorna el objeto iterable con el método subyacente __iter__(). Una vez iniciado el bucle, el método __next__() permite avanzar, en cada ciclo, al siguiente elemento hasta alcanzar el último. Cuando el puntero se encuentra en el último elemento si se ejecuta nuevamente el método __next__() el programa produce la excepción StopIteration:

 


lista = [10, 100, 1000, 10000]
iterador = iter(lista)
try:
    while True:
        print(iterador.__next__())        

except StopIteration:
    print("Se ha alcanzado el final de la lista")

Implementando una clase para iterar cadenas
Los métodos __next__() y __iter__() permiten declarar clases para crear iteradores a medida.


# Declara clase para recorrer caracteres de cadena de texto 
# desde el último al primer carácter

class Invertir:
     def __init__(self, cadena):
         self.cadena = cadena
         self.puntero = len(cadena)
     def __iter__(self):
         return(self) 
     def __next__(self):
         if self.puntero == 0:
             raise(StopIteration)
         self.puntero = self.puntero - 1
         return(self.cadena[self.puntero])

# Declara iterable y recorre caracteres

cadena_invertida = Invertir('Iterable')
iter(cadena_invertida)

for caracter in cadena_invertida:
     print(caracter, end=' ')

# Devuelven caracteres que restan por iterar (ninguno):

print(list(cadena_invertida.__iter__()))  # []

La función range()

Cuando se desea ejecutar un bucle un número de veces determinado se suele utilizar la función range() que genera un rango de valores numéricos iterables que no necesitan ser almacenados en una lista o tupla.
for elemento in range(1, 11):
    print(elemento, end=' ')  # 1 2 3 4 5 6 7 8 9 10 

for elemento in range(10, 0, -1):
    print(elemento, end=' ')  # 10 9 8 7 6 5 4 3 2 1    

Generadores

Los generadores son una forma sencilla y potente de iterador. Un generador es una función especial que produce secuencias completas de resultados en lugar de ofrecer un único valor. En apariencia es como una función típica pero en lugar de devolver los valores con return lo hace con la declaración yield. Hay que precisar que el término generador define tanto a la propia función como al resultado que produce.

Una característica importante de los generadores es que tanto las variables locales como el punto de inicio de la ejecución se guardan automáticamente entre las llamadas sucesivas que se hagan al generador, es decir, a diferencia de una función común, una nueva llamada a un generador no inicia la ejecución al principio de la función, sino que la reanuda inmediatamente después del punto donde se encuentre la última declaración yield (que es donde terminó la función en la última llamada).

# Declara generador

def gen_basico():
    yield "uno"   
    yield "dos"
    yield "tres"
   
for valor in gen_basico():
    print(valor)  # uno, dos, tres

# Crea objeto generador y muestra tipo de objeto

generador = gen_basico()
print(generador)  # generator object gen_basico at 0x7f75ffad55e8
print(type(generador))  # class 'generator'

# Convierte a lista el objeto generador y muestra elementos

lista = list(generador)
print(lista)  # ['uno', 'dos', 'tres']
print(type(lista))  # class 'list'



El siguiente generador produce una sucesión de 10 valores numéricos a partir de un valor inicial. 
El valor final se obtiene sumando 10 al inicial y el bucle se ejecuta mientras el valor inicial es menor 
que el final. El ejemplo muestra como se almacenan los valores de las variables en cada ciclo y el punto donde se reanuda el bucle en cada llamada.

def gen_diez_numeros(inicio):
    fin = inicio + 10    
    while inicio < fin:
        inicio+=1
        yield inicio, fin

for inicio, fin in gen_diez_numeros(23):
    print(inicio, fin)


En un generador la declaración yield puede aparecer en varías líneas e incluso dentro de un bucle. El intérprete Python producirá una excepción de tipo StopIteration si encuentra el comando return durante la ejecución de un generador.

¿Cómo Listar archivos con conflictos en Git?

En este MicoTip vamos a ver cómo resolver un dilema común al trabajar en git.

Es frecuente que luego de intentar un pull/merge desde repositorios de trabajo Git se generen conflictos entre archivos. La terminal nos indica dichos conflictos por medio del texto CONFLICT (así, en mayúsculas) al momento de generarse, pero ¿Qué pasa si no solucionamos el conflicto en el momento?

Por medio del comando git diff y un par de parámetros podemos listar dichos archivos en cualquier momento.

Podemos hacer solo un git diff dentro del directorio de nuestro proyecto así:

git diff

Y esto nos mostrará básicamente la diferencia de todos los archivos de tengan alguna diferencia en el repositorio.

Si quisieramos algo mas específico, podríamos, dentro del directorio de nuestro repositorio, tipear:

git diff --name-only --diff-filter=U

Esto nos mostrará los archivos con conflictos, caso contrario no mostrará nada en el terminal.

Así de Facil. Espero que les sea de utilidad.

 

¡Hasta la póxima!

Cómo Instalar PIP, Virtualenv y Django en Debian/Ubuntu.

Rescatando cosas del trastero (mi viejo blog), encontré un artículo interesante que aún me lo preguntan y que a veces yo mismo uso cuando tengo flojera de teclear comandos para montar un entorno de desarrollo. Y es justamante «cómo Instalar PIP, Virtualenv y Django en un sistema basado en debian…» Claro, claro… ya estamos años después, nuevos inventos, nuevas tecnologías, micro servicios, etc., pero por algo tenemos que empezar si estamos iniciandonos en el mundo de Django, Python y Linux y por eso les dejo el artículo (Además, le hago publicidad gratis a mi viejo y querído blog ;-P ) https://algoritmoselinventor.wordpress.com/2015/02/27/como-instalar-pip-virtualenv-y-django-en-debianubuntu/

¡Espero que les sirva tanto como a mí! ¡Hasta la próxima!

Cambiar contraseña de root de las maquinas virtuales con Xen

Esta es una entrada algo vieja de mi antiguo blog que ya está viejito y olvidado, pero creo que todavía nos puede servir así que se las dejo, (y de paso le hago propaganda a mi viejo blog ;-P) https://algoritmoselinventor.wordpress.com/2015/11/07/cambiar-contrasena-de-root-de-las-maquinas-virtuales-con-xen/

 

Espero que les sirva. ¡Hasta la próxima! 🙂

Cómo Ejecutar Diff a la salida de dos Comandos

Buen@s, días, tardes o lo que sea cuando lean esto.

Hoy les traigo otro micro tip que les puede ser de mucha utilidad y como ya leyeron el título, no les vuelvo a repetir de qué se trata, je je. OK, manos a la obra.

En uno de estos inventos locos, necesité ejecutar el comando diff sobre la salida de otros dos comandos. O sea, diff recibe como parámetros los ficheros sobre los que se quiere mostrar las diferencias, pero yo necesitaba hacer un diff a la salida de dos comandos, no dos ficheros. Por ejemplo:

Suponiendo que tengo dos directorios con esta estructura:

ejemplo/
├── archivo1.odt
├── archivo1.txt
├── archivo2.odt
└── archivo2.txt

Y un segundo directorio:

ejemplo2/
├── archivo1.odt
├── archivo1.txt
├── archivo2.odt
├── archivo2.txt
└── archivo3.txt

Y mi gran problema (hipotéticamente hablando) es saber la diferencia entre la salida de ejecutar «ls -l» en cada uno de los directorios.

Esto sería mas o menos así.

$ diff <(ls -l ejemplo) <(ls -l ejemplo2)
2,5c2,6
< -rw-r--r-- 1 usuario usuario 8099 mar 27 13:14 archivo1.odt
< -rw-r--r-- 1 usuario usuario   18 mar 27 13:07 archivo1.txt
< -rw-r--r-- 1 usuario usuario 8132 mar 27 13:14 archivo2.odt
< -rw-r--r-- 1 usuario usuario 18 mar 27 13:08 archivo2.txt 
--- 
> -rw-r--r-- 1 usuario usuario 8099 mar 27 13:25 archivo1.odt
> -rw-r--r-- 1 usuario usuario   18 mar 27 13:25 archivo1.txt
> -rw-r--r-- 1 usuario usuario 8132 mar 27 13:25 archivo2.odt
> -rw-r--r-- 1 usuario usuario   18 mar 27 13:25 archivo2.txt
> -rw-r--r-- 1 usuario usuario    0 mar 27 13:25 archivo3.txt

¡Genial! ¿no?

Esto, claro que lo podemos aplicar a una inmensidad de situaciones, como buscar la diferencia entre las salidas de un comando grep, listado de permisologías entre dos directorios de aplicación, búsqueda de dispositivos o lo que ustedes quieran.

Les dejo la referencia

Espero les haya servido. ¡Hasta la próxima!

May the force be with you!

 

 

 

Como Comparar Archivos de Texto en Linux desde la Consola

Este post va a ser un poco corto, pero veremos un tip que nos puede ayudar a salir de dudas y que puede salvarnos la vida(estoy hablando de nuestro trabajo xD) y es cómo comparar dos archivos de texto (que ha simple vista pueden parecer iguales) para determinar si realmente son iguales o no. Esto puede ser muy útil cuando estamos revisando, por ejemplo archivos con código fuente, archivos de configuración de alguna aplicación, algún respaldo de base de datos, etc.

El commando «diff»

El comando diff compara dos archivos línea a línea para detectar diferencias entre ellos. La sintaxis básicamente esta:

diff [parámetros] [archivo1] [archivo2]

La salida generalmente muestra todo el contenido diferente entre ambos archivos. El contenido referente al primer archivo pasado por argumento se muestra precedido por “<“, mientras que el referente al segundo archivo por “>”.

Si ejecutamos solo diff archivo1.txt archivo2.txt  sería algo como:

** Si son iguales

$ diff archivo1.txt archivo2.txt
$

** Si son diferentes

$ diff archivo1.txt archivo2.txt
1c1
< estoy en archivo1
---
> estoy en archivo2

Si utilizamos el mismo comando pero habiendo modificado uno de los archivos. Como puedes ver en el ejemplo.

Con el parámetro [-b] tenemos la opción de hacer la comparación igual que en el caso anterior, pero ignorando todos los espacios en blanco. El output en este caso es básicamente el mismo.

Y aunque se trata de un comando que se utiliza básicamente para comparar archivos de texto, también puedes utilizarlo para comparar archivos que estén en otros formatos, como odt, doc, docx, pdf, mp4, etc.

$ diff archivo1.odt archivo2.odt
$

En este caso he utilizado el comando (sin parámetros) para comparar dos archivos iguales en formato odt. Como ves, si no hay ninguna salida en el terminal, nos está indicando que los dos archivos que hemos pasado como parámetro son iguales. Si lo ejecuto con archivos diferentes, mostraría algo así:

$ diff archivo1.odt archivo2.odt
Los ficheros binarios archivo1.odt y archivo2.odt son distintos

Como ves, en este caso no muestra las diferencias (ya que son compimidos) pero igual nos dice que son distintos.

También podemos usar diff para comparar directorios con el parámetro [-r].

Suponiendo que tengo dos directorios con esta estructura:

ejemplo/
├── archivo1.odt
├── archivo1.txt
├── archivo2.odt
└── archivo2.txt

Y un segundo directorio:

ejemplo2/
├── archivo1.odt
├── archivo1.txt
├── archivo2.odt
├── archivo2.txt
└── archivo3.txt

Aplicando la comparación daría un resultado mas o menos así:

$ diff -r ejemplo ejemplo2
Sólo en ejemplo2: archivo3.txt

Como ves, este simple comando puede ser de gran utilidad. Algunos otros parámetros interesantes de este comando:


-a Trata todos los ficheros como de texto y los compara línea por línea, incluso si no parecen ser de texto.

-b Hace caso omiso de cambios referentes a la cantidad de espacio en blanco.

--brief
Informa solamente de si los ficheros difieren, no acerca de los detalles de las diferencias.

-i No hace caso de cambios en la caja tipográfica; considera las letras mayúsculas y minúsculas equivalentes.

-r (o --recursive) Cuando compara directorios, compara recursivamente cualesquier subdirectorios encontrados.

-q Informa sólo de si los ficheros difieren, no de los detalles de las diferencias.

-w Descarta espacio en blanco cuando compara líneas.

También existe otro comando derivado de este llamado diff3 que nos permite comparar tres archivos por terminal, pero para no hacer el cuento mas largo, puedes encontrar mas información sobre diff o diff3 ejecutando en la línea de comandos de tu distribución favorita lo siguiente:

# Para diff
man diff
# Para diff3
man diff3

Este comando también lo podemos usar para ver la diferencia entre la salida de otros dos comandos, pero esa es otra historia (ver aquí).

El commando «cmp»

Este es otro comando que compara dos archivos de texto al igual que diff, pero en este caso hace una comparación byte a byte. La sintaxis es muy similar:

$ cmp [parámetros] [archivo1] [archivo2]

Tambien sirve con archivos como doc, odt, pdf, mp4, etc., sin embargo en estos casos solo se limita a indicar si son iguales o no, sin señalar las diferencias:

$ cmp archivo1.odt archivo2.odt
archivo1.odt archivo2.odt son distintos: byte 11, línea 1

Como puedes observar, cuando usamos el comando (sin parámetros) sobre los dos archivos de texto del ejemplo anterior, cmp nos indica que los dos archivos son distintos, y además nos muestra el byte diferente y el número de línea a que corresponde en el texto.

$ cmp -b archivo1.odt archivo2.odt
archivo1.odt archivo2.odt son distintos: el byte 11, en la línea 1 es 12 ^J 317 M-O

Con el parámetro [-b], si hay diferencias entre los dos archivos cmp nos indica como output el byte diferente, el número de línea y el contenido que varía.

Bueno, espero que les haya servido y nos vemos en otro artículo.

May the force be with you!

 

Introducción a la administración de dispositivos en sistemas Linux modernos

¡Hola!

Esta va ser una entrada muy corta, es algo que ví por ahí que me pareció interesante compartir ya que sé que a muchos nos ha causado inquietud o problemas alguna vez…

¿Cómo funciona la administración de dispositivos en un sistema Linux?, ¿Cómo se autodetectan las unidades? ¿Cómo hacen los explodaroes de archivos para detectar los USB, SD, etc.? Bueno, por aquí comienza la cosa…

Las distribuciones modernas de Linux son capaces de identificar un componente de hardware que está conectado a un sistema ya en funcionamiento. Hay muchas distribuciones fáciles de usar como Ubuntu,  que ejecutan automáticamente aplicaciones específicas como Rhythmbox cuando un dispositivo portátil como un iPod está conectado al sistema.

El Hotplugging (que es la palabra utilizada para describir el proceso de insertar dispositivos en un sistema en ejecución) se logra en una distribución de Linux mediante una combinación de tres componentes: Udev, HAL y Dbus.

Udev proporciona un directorio de dispositivos dinámicos que contiene sólo los nodos de los dispositivos conectados al sistema. Crea o elimina los archivos de nodo del dispositivo en el directorio /dev a medida que se conectan o se extraen.

Dbus es como un bus de sistema que se utiliza para la comunicación entre procesos.

El HAL obtiene información del servicio Udev, cuando un dispositivo se conecta al sistema y crea una representación XML de ese dispositivo. A continuación, notifica la aplicación de escritorio correspondiente como Nautilus a través del Dbus y Nautilus abrirá los archivos del dispositivo montado.

El artículo de Linux.com al que estoy haciendo referencia, se centra sólo en Udev, que hace la identificación básica del dispositivo. Así que describo algo del tema para ustedes.

¿Qué es Udev?
Udev es el administrador de dispositivos para el kernel Linux 2.6 que crea/elimina de forma dinámica los nodos del dispositivo en el directorio /dev. Es el sucesor de devfs y hotplug. Se ejecuta en el espacio de usuario y el usuario puede cambiar los nombres de dispositivo utilizando las reglas Udev.

Udev depende del sistema de archivos sysfs que fue introducido en el kernel 2.5. Es sysfs lo que hace que los dispositivos sean visibles en el espacio del usuario. Cuando se agrega o se elimina un dispositivo, se producen eventos del kernel que notificarán a Udev en el espacio de usuario.

El binario externo /sbin/hotplug se utilizó en versiones anteriores para informar a Udev acerca del cambio de estado del dispositivo. Eso ha sido reemplazado y Udev ahora puede escuchar directamente esos eventos a través de Netlink.

¿Por qué lo necesitamos?
En los kernels antiguos, el directorio /dev contenía archivos de dispositivos estáticos. Sin embargo, con la creación dinámica de dispositivos, se crean nodos de dispositivos para sólo aquellos dispositivos que realmente están presentes en el sistema.

Udev proporciona un sistema de nombres de dispositivo persistente a través del directorio /dev, facilitando la identificación del dispositivo.

Si quieres saber más a cerca del tema, Este es el articulo original. Introduction to Device Management In Modern Linux System