Quitar códigos de barra duplicados

[Bash] [Script]

Lo que traigo el día de hoy es un script de Bash que lee un txt con información, busca entre varias columnas, extrae la información necesaria, compara algunos campos, hace otras comprobaciones y finalmente borra del archivo original únicamente las líneas que se solicitan (a la par que elabora un respaldo en otro archivo), todo esto solamente en unas cuantas líneas de código divididas en dos scripts.

Si les interesa ir directo a ver el código se encuentra en mi github : delBarCodesDup

Este pequeño proceso me tomó aproximadamente unas 7 horas de trabajo ya que fue necesario leer toda la documentación que encontré de algunos comandos que en mi vida había utilizado conscientemente, entre los que se destacan awk, sed y sord, si los conoces ya sabes por dónde va el asunto.

En la empresa donde laboro utilizamos catálogos, como existen diferentes proveedores que venden los mismos productos pero no precisamente al mismo precio, a veces necesitamos discriminar algunos. Pero ¿Qué pasaría si yo prefiero a un proveedor que vende más caro por otras facilidades o garantías que vienen con ese costo?

Entonces lo que realiza el script es sencillo simplemente tenemos que ir a consultar los códigos de barras y rescatar los duplicados, en seguida comparar los precios y dejar únicamente los más altos dentro del catálogo que se tomará como referencia para hacer los pedidos.

Con eso podemos hacernos una idea de lo que tenemos y lo que necesitamos, el primer problema es que el código de barras no está en la primera posición, el segundo es que vamos a necesitar también el precio de venta y no está contiguo al código de barras por lo que debemos buscarlo.

Para trabajar vamos a hacer la siguiente estructura un directorio principal que es donde guardaríamos los scripts (extrae.awk y script.sh)y un directorio secundario de nombre tmp que contendría el catálogo y los archivos temporales que se necesitan, esto para poder usar git en todo momento y no exponer los datos sensibles en caso de haberlos (es importante borrar los archivos temporales antes de volver a ejecutar el script, o agregar dentro del mismo unas líneas que borren los archivos al inicio).

A grandes rasgos lo que hay que resaltar del archivo extrae.awk son tres partes:

ARGV[1]="tmp/Catalogo.txt"

Esta variable indica el archivo sobre el cuál se va a trabajar (en el ejemplo es un archivo de nombre Catalogo.txt dentro de la carpeta tmp).

FIELDWIDTHS="10 14 81 8"

Esta línea delimita los caracteres a los cuales vamos a cortar el texto haciendo una especie de columnas. La primera columna consta de 10 caracteres a partir del primero, la segunda de 14 a partir del carácter 11, etc. Cabe aclarar que lo que esté fuera de estos rangos va a ser ignorado por el script.

{print $2 "." $4 "." a++}

La última parte a resaltar de este script va ligada con la anterior ya que está mandando a “imprimir” (o más bien mostrar en consola) lo que se encuentra en la variable número 2 (o sea los 14 caracteres), luego pone un punto en seguida la variable 4 (los 8 caracteres), y después de otro punto una variable que va aumentando por cada línea que imprime la cuál será el número de línea que estamos leyendo.

Lo siguiente es comenzar a acomodar la salida del anterior script ya que si se ejecuta saldría algo parecido a esto:

engell@oakenshield:~/delBarCodesDup$ awk -f ./extrae.awk
A7501043161602.  368072.1
A7502216798373.    2347.2
A7506272401932.     789.3
A7501281200101.     467.4

Como podemos ver la respuesta es el código de barras, seguido de los números correspondientes al precio y enseguida el número de línea en el que se encuentra cada dato, todo esto dividido con puntos que delimitan los diferentes campos. Teniendo esta información correcta ya habríamos terminado con ese script y lo siguiente es jugar con los resultados que te da el mismo con modificadores.

Para ello podemos usar varios, el primero que vamos a ver es sed ya que es más fácil trabajar únicamente con números, así que cambiamos todos los espacios por ceros que sería agregando esta línea al final del script:

| sed 's/ /0/g'

Luego ordenamos los resultados y si hay duplicados los va a poner seguidos con:

| sort

En seguida le decimos que nos muestre únicamente los que tengan los primeros 14 caracteres repetidos y con el modificador -d dices que te muestre sólo el primero:

| uniq -d -w 14

Volvemos a cortar el texto cada que encuentre un punto y separamos únicamente el tercer campo (con esto estamos extrayendo únicamente el número de línea):

| cut -d "." -f 3

Para finalizar ordenamos numéricamente de forma invertida (de mayor a menor) y guardamos los resultados en el archivo tmp/cat:

| sort -g -r >> tmp/cat

Entonces tenemos una línea que hace todo el trabajo hasta dejar únicamente el archivo tmp/cat con las líneas a borrar:

awk -f "./extrae.awk" | sed 's/ /0/g' | sort | uniq -d -w 14 | cut -d "." -f 3 | sort -g -r >> tmp/cat

A este archivo le vamos a agregar al final de cada línea una d ya que se necesita para quitar líneas con el comando awk:

sed -i 's/$/d/' 'tmp/cat'

Ahora sólo necesitamos correr un loop como el siguiente:

for linea in $(man tmp/cat); do
   num=$(echo $linea | sed 's/.$//g')
   awk "NR==$num" tmp/Catalogo.txt >> tmp/less
   sed -i $linea tmp/Catalogo.txt
done

Que lo que hace es básicamente: Por cada línea en el archivo tmp/cat crea una variable num que contiene el texto (en este caso el número de line más una d) quitándole el último carácter (la d). Luego guarda la línea número num en el archivo tmp/less. Por último elimina la línea del archivo tmp/Catalogo.txt (que sería el archivo original)

Eso sería la explicación detallada del script. Si a alguien le sirve que se sienta libre de usarlo y/o modificarlo como le sea conveniente. Nos leemos pronto.

 
comments powered by Disqus