jueves, 5 de febrero de 2009

Condimento al gusto de HAL (II)

[... continuación de la entrada anterior]

Evidentemente, nuestra tarea ha finalizado. Cada tarea parcial ha sido resuelta y podemos construir la orden completa, que sería: [Recuérdese el uso del signo '\', explicado el día pasado, para separar líneas de órdenes largas]:

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


Podemos ver el resultado, que se ha guardado en el fichero jargon_ref, pidiendo a HAL que nos lo muestre, por ejemplo, con una orden que comentamos en otra sesión:

more jargon_ref

Una consideración simple del resultado suscita inmediatamente tres objeciones ---en realidad, cuatro, pero la cuatro la dejamos para más tarde:

  1. Las referencias están ahí, pero desordenadas. ¿No sería lógico, después de tanto trabajo, obtener, al menos, una lista alfabéticamente ordenada?

  2. No es aceptable que HAL guarde en un fichero el resultado sin mostrarlo antes. ¿Habrá alguna forma de conseguir que lo muestre y lo guarde a la vez?

  3. Si volvemos a hacer una consulta al Jargon File sobre un artículo distinto, el fichero jargon_ref almacenará las referencias de este último, pero borrará las que ya existían. Debemos modificar la redirección para arreglar este defecto.

  4. ... ??


Todas estas cuestiones no hacen sino refinar, por una parte, el propio planteamiento del problema (cuestiones 1, 2 y 3) y, por otra, poner en evidencia, que en la división de tareas que realizamos no fuimos totalmente fieles a dicho planteamiento (¿cuestión 4?).

Recordemos la forma exacta en que se planteó el problema, expresado entonces bajo el atuendo de un deseo:

Sería magnífico disponer de una lista con las referencias que constan en los artículos que vamos leyendo y guardarla en un fichero.


Refinemos el propio planteamiento para que tenga en cuenta las tres primeras objeciones:

Sería magnífico ver una lista ordenada con las referencias que constan en los artículos que vamos leyendo y a la vez añadirla a un fichero que contendría las referencias cruzadas de todos los artículos que hayamos consultado previamente.


Las nuevas tareas que surgen de esta nueva versión del problema son, expresadas con precisión:

  1. Ordenar alfabéticamente la lista generada por grep antes de que awk le dé el formato requerido.

  2. Redirigir la salida de awk para que se añada al fichero jargon_file, en lugar de sobreescribirlo. Y, preferentemente, hallar un procedimiento para que, a la vez, nos muestre el resultado actual de su procesamiento.



Ordenar alfabéticamente es muy simple. Podemos pedirle a HAL que "arregle" o "clasifique" (sort en inglés) un fichero alfabéticamente, simplemente diciéndoselo:

sort FICHERO

¡Divino, qué bien sienta el aire puro de las órdenes triviales, sobre todo después de nuestro descenso a los infiernos!

Como muchas otras órdenes de HAL, si no se da un nombre de fichero como argumento, el flujo de texto lo toma del dispositivo de entrada. Por tanto, podemos introducir un simple sort en una tubería entre el grep y el awk de nuestra orden inicial:

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


Conseguir redirigir la salida de una orden a un fichero y a la vez mostrarla en pantalla es igualmente sencillo con la orden tee ---más aire puro para nuestras neuronas. tee hace las veces de una 'T' en nuestro arsenal de fontanería ---de ahí su nombre: la pronunciación de la 't' en inglés. Lo que entra en ella sale directamente sin mayor modificación, pero a la vez se redirige al fichero que se le dé como argumento (si el fichero no existe, lo crea por nosotros):

(flujo de entrada) ============= (flujo de salida)
|
|
|
fichero


Por ejemplo, si quiero ver y guardar la lista de mis ficheros en el fichero mis_ficheros, le diría a HAL:

ls | tee mis_ficheros

Para mayor deleite, tee dispone de la opción -a (de append, que significa "añadir al final"), cuyo propósito es justo lo que ahora nos interesa, a saber, redirigir la entrada al fichero que le demos como argumento, pero sin sobreescribirlo. Y, de modo semejante a como sucedía con el operador de redirección >>, (el "embudo doble"), tee -a funciona igual que tee a secas cuando el fichero dado como argumento no existe.

En definitiva, podemos sustituir la ineficaz redirección que formaba parte de nuestra orden primitiva por un tee -a empalmado mediante una tubería al resto de la orden y resolver de un plumazo la segunda tarea [llamaré ahora jargon_refs, en lugar de jargon_ref al fichero de destino, para verificar desde cero el comportamiento global de nuestra orden modificada]:

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


¿Qué tal, HAL, otra prueba más con esta orden?

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


HAL nos muestra las referencias cruzadas para hacker ethic y guarda la salida en el fichero jargon_refs, que ahora presenta el siguiente aspecto, como puede comprobarse si le insistimos a HAL para que nos lo muestre con more jargon_refs:

hacker:
{bogus}
{cracker}
{geek}
{hacker ethic}
{hack value}
{Internet address}
{the network}
{wannabee}
hacker ethic:
{FidoNet}
{GNU}
{gray hat}
{samurai}
{superuser}
{tiger team}
{Usenet}

Hemos dado fin a nuestra ya bastante larga expedición por los confines de la lengua de HAL. Pero, sin duda, cualquier lector atento que haya llegado hasta aquí se preguntará si no es posible generalizar nuestra solución ya refinada. Tanto esfuerzo como el empleado no merecería menos. ¿No sería posible aliviar definitivamente al humano y construir una instrucción elemental a partir de la que hemos logrado?

Ésta, evidentemente, es la cuarta objeción, por la que antes, y adrede, pasamos de puntillas. El lector está en su pleno derecho de plantearla y de que se le responda. Pero ello nos llevaría a acometer una nueva y muy arriesgada aventura, ya en terrenos en los que sólo los exploradores más incansables osarán aventurarse, territorios donde abandonamos el ámbito del diálogo unívoco con HAL y nos adentramos en el universo de la programación. Que el autor esté dispuesto a emprender esa epopeya, aun en escala mínima, es algo que hasta él mismo ignora. Sea como fuere, aún quedan unos cuantos lugares menos escarpados por explorar.


Resumen

  • Un aspecto importante en la resolución de problemas consiste en aceptar la posibilidad de tener que reformular o precisar el propio planteamiento del problema en una fase intermedia del proceso que lleva a su solución.

  • La orden sort permite ordenar un flujo de texto.

  • La orden tee permite conducir el flujo de entrada hacia la salida y a la vez almacenarla en un fichero.

  • Generalizar la solución de un problema implica casi siempre utilizar técnicas de programación.

No hay comentarios:

Publicar un comentario