miércoles, 24 de junio de 2015

Trocear parámetros de la línea de comando (comando xargs)

Hoy os voy a contar la solución a un pequeño problema que se me ha presentado hace unos días, y así aprovecho para contaros una cosa que no sabía y que he acabado utilizando del comando xargs.

El caso es que tenemos un script que procesa cadenas de texto y compone con ellas una cadena más grande. En concreto, las cadenas son una serie de valores con los que el script compone la condición de una instrucción SQL (una select) del estilo

select campo1, campo2...
from tabla
where dato in ('dato1', 'dato2', 'dato3'...)

Esos dato1, dato2... son los parámetros que se le pasan al script.

Queda más claro viendo la Fig. 1.

Fig. 1. Salida del script que genera instrucciones SQL con cláusula "in"


Como es fácil imaginar, el script no está pensado para ejecutarlo manualmente, sino que las cadenas a incluir proceden de una lista existente en un fichero de texto plano. He sustituido los datos reales por basura, pero más o menos, algo así:

Fig. 2. La lista de valores a procesar. Imaginativa, ¿a que sí? Lo que yo decía...

Hay que aclarar que el script no procesa la entrada estándar, en cuyo caso podríamos haber utilizado los pipes (tuberías), sino que espera que le llegue la lista de cadenas (datos) como parámetros. Es decir, los extrae de la variable $argv (es un script PHP).

Una forma fácil de pasarle los valores al script podría ser utilizando las comillas simples invertidas para ejecutar el comando cat y luego la salida de este comando que se sustituya en la línea de comandos de la llamada a nuestro script. No os compliquéis leyendo de nuevo lo que he dicho, queda más claro leyendo el código de la Fig. 3. Vamos, algo así:


Fig. 3. Uso de las comillas simples invertidas para pasar los parámetros al script

Otra solución podría ser utilizar el programa xargs. ¿Y qué hace este programa? Básicamente, recoge todo lo que haya en su entrada estándar y se lo pasa como parámetros al programa que le digamos. Se entenderá mejor con un ejemplo: vamos a ver en la Fig. 4 cómo conseguir lo que hemos hecho antes utilizando xargs en vez de las comillas invertidas.


Fig. 4. Uso de xargs para conseguir el mismo resultado que antes

Hasta aquí vemos dos formas en apariencia más o menos equivalentes (de momento, no entraremos a hablar de rendimiento) de hacer lo mismo. Sin embargo, el problema que estamos resolviendo tiene una peculiaridad más, y aquí ya veremos cómo ambas formas de hacerlo ya no nos valen por igual.


TROCEAR LA ENTRADA

La lista a procesar tiene muuuuuuuuuuchos valores, más de diez mil. En vez de que se nos genere una cláusula "in" monstruosamente grande, lo que queremos es trocear la consulta en diferentes consultas que iremos dosificando poco a poco a la base de datos, a fin de no saturarla y poder ir obteniendo resultados parciales. O por los motivos que sea, que ahora mismo dan igual.

Y aquí es donde se revela una ventaja muy importante de xargs: la capacidad de generar no una, sino N llamadas al comando indicado, pero dándole "bloques" de argumentos del tamaño que queramos. Es decir, en vez de llamar una sola vez al script, y en esa llamada pasarle todos los parámetros de golpe, puede que queramos ir pasándole los argumentos de 10 en 10, pongamos por caso, y que nos devuelva las diferentes SQL con los parámetros de cada bloque.

¿Y cómo se consigue esto: simplemente con la opción -nX del comando xargs, donde debemos sustituir X por el número que indique cuántos parámetros se le pasarán al comando en cada llamada. Así, por ejemplo, si queremos pasarle los argumentos de 10 en 10, pondríamos lo siguiente:


Fig. 5. Pasando los parámetros al script en bloques de 10

En este caso, la lista que he utilizado tiene sólo 29 elementos, así que podemos ver que en la última SELECT se han utilizado los 9 últimos que quedaban, y no 10 argumentos, como en las dos llamadas anteriores. Es decir, que si el script está pensado para recibir un número fijo de parámetros, hay que tener en cuenta que al trocearlos, es posible que la última invocación no incluya todos los necesarios.

Una cosa interesante es que si invocáis a xargs con la opción -t, podéis ver qué se ejecutará sin llegar a ejecutarlo de verdad, sólo se muestra la línea de comando que se ejecutaría. Esto viene bien para hacer pruebas antes de lanzar la llamada definitiva.

No me extiendo más, pero os sugiero que le dediquéis un rato a la página del manual del comando xargs, que posiblemente amortizaréis el tiempo empleado en ello.

Que ustedes tengan un buen tecleo.

PARA SABER MÁS

1. En español: http://systemadmin.es/2009/04/uso-de-xargs-herramientas-unix-ii#

2. En inglés: https://en.wikipedia.org/wiki/Xargs

No hay comentarios:

Publicar un comentario