miércoles, 18 de febrero de 2009

Más variables para HAL

El día pasado creamos nuestro primer guión y convertimos en algo fácil de recordar y ejecutar una orden compleja que resultó ardua de escribir y que sería insoportable tener que volver a reproducir cada vez que queremos realizar la tarea para la que fue diseñada.

Hoy vamos a seguir los mismos pasos con otra orden, también compleja, la que constituyó la coronación de nuestros esfuerzos en la primera parte de esta serie de conversaciones. Es recomendable que el lector relea por encima los dos últimos pasos de aquellos artículos, que se titularon "Condimentos al gusto de HAL" (I y II).

Recordemos que la orden compleja que entonces creamos fue ésta:

dict -d jargon hacker \
| grep -E -o '[{][^[:punct:]]+}' \
| sort \
| awk 'BEGIN {FS="\n"; print "hacker:"} { print " " $1 }' \
| tee -a jargon_refs

Su propósito era mostrar en pantalla todas las referencias cruzadas a artículos del Jargon File contenidas en el artículo hacker de ese mismo diccionario y guardarlas, además, en el fichero jargon_refs donde se almacenarían junto con otras series de referencias que hubiesen aparecido en anteriores consultas.

Entonces se planteo una objeción obvia, a la que no dimos respuesta: ¿por qué no generalizar el resultado?

Ahora, por fin, disponemos de un recurso para proceder a una generalización básica de la citada orden. Merece la pena prestar atención a la estrategia que vamos a seguir, porque abre por vez primera las puertas hacia una conversación realmente inteligente con nuestro querido HAL.

Lo primero es crear, como el día pasado, un guión con esa orden, digamos, buscar_en_jargon. Nos movemos al directorio guiones. Abrimos el editor, como de costumbre, dándole como argumento el nombre de fichero indicado. Copiamos la orden y guardamos la edición. Podemos ahora salir del editor o, mejor, enviarlo al trasfondo con Ctrl+Z, porque vamos a tener que reeditar el guión en breve. Finalmente cambiamos el modo del fichero para que al menos nosotros podamos ejecutarlo... Está bien, recordaremos una vez más cómo se hace, pero a ver si es la última:

chmod u+x buscar_en_jargon

Si ahora le pedimos amablemente a HAL que interprete nuestro nuevo guión:

./buscar_en_jargon

nos mostrará exactamente el mismo resultado que obtuvimos antaño, o sea, la lista de todas las referencias cruzadas del término hacker en el Jargon File.

No estamos hoy en ninguna fecha especial, salvo por el hecho de que hace dos días ha salido de la fábrica la tan esperada nueva versión estable de Debian y muchos usuarios puede que hayan actualizado hoy mismo la suya con un sencillo aptitude dist-upgrade.

Pero da igual el día, cualquier día es bueno para pedir deseos. Y qué mejor deseo que imaginar que HAL pudiera entender algo como esto:

./buscar_en_jargon distro

Es decir, que pudiésemos introducir un argumento para nuestra orden buscar_en_jargon, como hacemos con otras órdenes, y que pudiésemos así evitarnos el estúpido trabajo de tener que editar el fichero que la contiene cada vez que quisiésemos buscar en el Jargon una palabra distinta a hacker.

HAL puede cumplir nuestro deseo. Dispone de un medio para hacerlo. Ese medio es una cosa muy pequeña, una sencilla variable interna. Tiene esta humilde forma, que quizá no nos resulte del todo extraña:

$1

Veamos cómo funciona. Aunque se pueden poner ejemplos de su uso directamente desde la línea de órdenes, el funcionamiento de este parámetro posicional ---como se denomina técnicamente--- y de sus congéneres ($0, $2, $3, etc.) se entiende con mucha mayor naturalidad si creamos un guión.

Vamos a llamar a nuestro guión, saludo_tontorron. Consta de las siguientes líneas:

echo $0
echo $1
echo $2

Tras guardarlo y cambiarle el modo, lo ejecutamos de esta forma:

./saludo_tontorron hola amigos

El resultado será:

./saludo_tontorron
hola
amigos

¿Qué ha sucedido? Muy simple. HAL lee y ejecuta línea a línea nuestro saludo_tontorron. Cada línea consta de una instrucción echo que toma como argumento un parámetro posicional. Como sabemos de otro día, cuando el argumento de echo es una variable ---como los son $0, $1 y $2--- devuelve el valor de esa variable. El valor de la variable $0 es la orden ejecutada; el de la variable $1, el primer argumento; el de la $2, el segundo; etc.

Algo tan simple es extraordinariamente útil. Cada orden que ejecutamos es analizada miembro a miembro por HAL (donde cada miembro, como sabemos, está separado, por defecto, por un espacio). HAL guarda, además, temporalmente cada uno de los componentes de la orden en un parámetro posicional. De este modo, y mientras se ejecuta la orden, podremos reutilizar el valor de sus componentes.

La aplicación para nuestro caso es inmediata. En nuestro guión buscar_en_jargon, la primera línea era ésta:

dict -d jargon hacker

La orden la ejecutábamos luego sin argumentos:

./buscar_en_jargon

Al analizar HAL esta última orden, guardara el único miembro de la orden ./buscar_en_jargon en el parámetro posicional $0. Pero si al ejecutarla le añadiésemos un argumento, ese argumento se guardaría en el parámetro posicional $1. O sea, que si nuestra orden hubiese sido:

./buscar_en_jargon hacker

la palabra hacker se habría guardado en el parámetro $1. Y, si en lugar de hacker, hubiésemos puesto cualquier otro término, sería este otro término el que habría quedado almacenado en $1.

Procedemos, pues, a reeditar nuestro guión de tal forma que en lugar del término concreto hacker aparezca $1, cuyo valor será, en consecuencia, sustituido, por el primer argumento que demos a nuestro guión al ejecutarlo. Comentamos también el resto de líneas, que HAL dejará de ver, para poder ir probando paso a paso nuestra nueva y maravillosa adquisición. El guión remozado quedaría así:

dict -d jargon $1 \
#| grep -E -o '[{][^[:punct:]]+}' \
#| sort \
#| awk 'BEGIN {FS="\n"; print "hacker:"} { print " " $1 }' \
#| tee -a jargon_refs

Le toca al lector disfrutar a lo grande con el resultado del cambio, por ejemplo:

./buscar_en_jargon hacker

O, por qué no:

./buscar_en_jargon Linux


Resumen

  • HAL analiza pieza a pieza las órdenes que se ejecutan desde la línea de órdenes y guarda temporalmente el contenido de cada componente de dicha orden en variables internas denominadas parámetros posicionales.

  • Los parámetros posicionales son $0, $1, etc., donde el valor de $0 es la orden ejecutada en la línea de órdenes; el de $1, el de su primer argumento; etc.

2 comentarios:

  1. Hola, sigo leyendo toda esta serie con gran interés. No sólo aprendes cosas sino que está muy bien redactada. Un par de detalles:

    1. En la línea "HAL lee y ejecuta línea a línea nuestro guion_tontorron.", debería haber sido saludo_tontorron.

    2. En el guión remozado, has comentado todas las líneas excepto la primera. Yo creo que la almohadilla del principio sobra.

    ¡Sigue así!

    ResponderEliminar
  2. Corrijo el primer error, gracias por indicarlo.

    En cuanto a lo segundo que me indicas, no me queda claro a qué te refieres. El guión remozado es "una línea" dividida en partes (mediante el signo '\') para que sea más legible. De todas sus partes, he comentado (es decir, prefijado con el signo de almohadilla) todas menos la primera, o sea,

    dict -d jargon $1 \

    ¿A qué te refieres con lo de "la almohadilla del principio"?

    ResponderEliminar