En linux, existe un comando llamado locate que busca archivos en nuestro sistema de ficheros haciendo consultas a una base de datos, la descripción según su man es:

Locate lee una o más bases de datos preparadas por updatedb y escribe a la salida estandar los nombres de los archivos que coincidan con al menos uno de los patrones, uno por línea.

El motivo de este artículo viene dado por un problema que me planteé hace unos días. Resulta que tengo en un archivo los nombres de algunas de mis canciones preferidas. Este archivo lo voy actualizando regularmente y quería generar una lista de reproducción en base a dicho fichero. Así que he creado un script que recorre todos los elementos del archivo y busca dónde se encuentra el fichero en mi disco duro.

Índice

Expresiones regulares en Locate



Locate acepta expresiones regulares complejas, para ello hay que llamarlo con la opción -regex.

El problema básicamente es el siguiente. A partir de un texto con los nombres parciales de un fichero obtener la ruta completa a dicho archivo. Lo de parciales quiere decir que si el nombre es Autor - Nombre Canción, en el texto solo se guarda Nombre Canción.

Crear la expresión regular

Empezaré mostrando la expresión regular y luego la explicaré:

$i.*(\.mp4|\.mp3)

En $i está el nombre de la canción, .* permite que haya cero o más caracteres tras el nombre de la canción y finalmente (\.mp4|\.mp3) obliga a que la extensión del fichero sea mp3 o mp4.

Siempre que necesito crear una expresión regular uso una herramienta llamada regex tester que permite visualizar qué cadenas de texto coincidirían con el patrón:

Créditos: inconfinder

Script completo

Con la expresión regular construida, solo resta crear un script que procese el texto con el nombre de las canciones y cree la lista de reproducción:

#!/bin/bash

nombres=`cat ARCHIVO_CON_LISTA_DE_NOMBRES`

IFS='
'

> /RUTA/A/LISTA/DE/REPRODUCCION/LISTA.m3u

for i in $nombres
do
    echo "locate --regex -i \"$i.*(\.mp4|\.mp3)\""
    locate --regex -i "$i.*(\.mp4|\.mp3)" | tee -a /RUTA/A/LISTA/DE/REPRODUCCION/LISTA.m3u
done
IFS=' '

IFS se establece al salto de línea para que el for tome como separación cada línea del archivo, en lugar de un espacio (valor por defecto de IFS). De esta forma, si una línea del fichero contiene Nombre canción, en el for el contenido de $i valdrá Nombre canción y no Nombre y en la siguiente iteración canción. > /RUTA/A/LISTA/DE/REPRODUCCION/LISTA.m3u borra el contenido de lo que tuviera la lista anteriormente para generarla de nuevo. Por último, la tubería con tee permite escribir tanto a la salida estándar como a la lista.

Otra opción, sugerida en Twitter por @ingenieríainv, es usar un while read $i:

#!/bin/bash

nombres=`cat ARCHIVO_CON_LISTA_DE_NOMBRES`

> /RUTA/A/LISTA/DE/REPRODUCCION/LISTA.m3u

cat $nombres | while read i
do
    echo "locate --regex -i \"$i.*(\.mp4|\.mp3)\""
    locate --regex -i "$i.*(\.mp4|\.mp3)" | tee -a /RUTA/A/LISTA/DE/REPRODUCCION/LISTA.m3u
done

Referencias