3. Leyendo ficheros de Entrada

En el programa awk típico,  toda la entrada se lee de la entrada estándar (normalmente el teclado) o de los fichero cuyos nombres se especifican en la línea de comando de awk. Si especificas ficheros de entrada, awk lee los datos del primer fichero hasta que alcanza el final del mismo; después lee el segundo fichero hasta que llega al final, y así sucesivamente. El nombre del fichero de entrada actual puede ser conocido por la variable implícita FILENAME (Ver la sección 12. Variables Implícitas (Built-in).

La entrada se lee en unidades llamadas registros, y éstos son procesados por las reglas uno a uno. Por defecto, cada registro es una línea del fichero de entrada. Cada registro leído es dividido automáticamente en campos, para que puedan ser tratado más fácilmente por la regla. En raras ocasiones necesitarás usar el comando getline, el cual puede realizar entrada explícita de cualquier número de ficheros (Ver la sección Entrada explícita con getline)

Cómo se particiona la Entrada en Registros

El lenguaje awk divide sus registros de entrada en campos. Los registros están separados por un carácter llamado el separador de registros. Por defecto, el separador de registros es el carácter newline. Por lo tanto, normalmente, un registro se corresponde con una línea de texto. Algunas veces puedes necesitar un carácter diferente para separar tus registros. Puedes usar un carácter diferente mediante la llamada a la variable empotrada RS (Record Separator).

El valor de RS es una cadena que dice como separar los registros; el valor por defecto es “\n”, la cadena formada por un único carácter newline. Esta es la razón por la cual un registro se corresponde, por defecto, con una línea.

RS puede tener cualquier cadena como valor, pero solamente el primer carácter de la cadena se usará como separador de registros. El resto de caracteres de la cadena serán ignorados. RS es excepcional en este sentido; awk usa el valor completo del resto de sus variables implícitas.

Puedes cambiar el valor de RS en un programa awk con el operador asignación, ‘=’ (Ver la sección Expresiones de Asignación). El nuevo carácter separador de registros de entrada debería estar entre comillas para que sea una constante cadena. A menudo, el momento adecuado para hacer esto es el principio de la ejecución, antes de procesar ninguna entrada, de modo que el primer registro sea leído con el separador apropiado. Para hacer esto, use el patrón especial BEGIN (Ver la sección Los Patrones Especiales BEGIN y END). Por ejemplo:

awk 'BEGIN { RS = "/" } ; { print $0 }' Lista–BBS

cambia el valor de RS a “/”, antes de leer ninguna entrada. Esta es una cadena cuyo primer carácter es una barra; como resultado, los registros se separarán por las barras. Después se lee el fichero de entrada, y la segunda regla en el programa awk (la acción sin patrón) imprime cada registro. Debido a que cada sentencia print añade un salto de línea al final de su salida, el efecto de este programa awk es copiar la entrada con cada carácter barra cambiado por un salto de línea. Otra forma de cambiar el separador de registros es en la línea de comandos, usando la característica asignación de variable (Ver la sección 14. Invocación de awk).

awk '...' RS="/" source–file

Esto fija el valor de RS a ‘/’, antes de procesar source–file.

La cadena vacía (una cadena sin caracteres) tiene un significado especial como valor de RS: significa que los registros están separados solamente por líneas en blanco. Ver la sección Registros de múltiples líneas, para más detalles.

La utilidad awk guarda el número de registros que han sido leídos hasta el momento del fichero de entrada actual. Este valor es almacenado en la variable implícita llamada FNR. Esta variable es inicializada a cero cuando se cambia de fichero. Otra variable implícita, NR, es el número total de registros de entrada leídos de todos los ficheros. Comienza en cero pero nunca es automáticamente reseteada a cero.

Si cambias el valor de RS a mitad de la ejecución de un programa awk, el nuevo valor se usa para delimitar los registros siguientes, pero el registro que esta siendo procesado en ese momento (y los registros ya leídos) no se ven afectados.

Examinando campos

Cuando awk lee un registro de entrada, el registro es automáticamente separado o particionado por el intérprete en piezas llamadas campos. Por defecto, los campos son separados por espacios en blanco, al igual que las palabras de una frase. Los espacios en awk significan cualquier cadena de uno o más espacios y/o tabuladores; otros caracteres tales como newline, formfeed, etc … que son considerados como espacios en blanco por otros languajes no son considerados como espacios en blanco por awk.

El propósito de los campos es facilitar al usuario la referencia a las partes constituyentes de un registro (tratar las subpartes de un registro). No tienes que usarlos – puedes operar con el registro completo si es lo que deseas – pero los campos son los que hacen a los programas awk más sencillos tan potentes.

Para referirse a un campo en un programa awk, usas un signo de dólar ‘$’, seguido por el número de campo que desees. Por lo tanto, $1 se refiere al primer campo, $2 se refiere al segundo, y así sucesivamente. Por ejemplo, supón que lo siguiente es una línea del fichero de entrada:

This seems like a pretty nice example.

Aquí el primer campo, o $1, es ‘This’; el segundo campo, o $2, es ‘seems’; y así sucesivamente. Advierta que el último campo, $7, es ‘example.’. Ya que no hay espacios en blanco entre la ‘e’ y el punto final de la frase ‘.’, el punto se considera como parte del campo séptimo.

No importa cuantos campos existan, el último campo de un registro puede ser representado por $NF. Por lo que, en el ejemplo anterior, $NF sería lo mismo que $7, o lo que es lo mismo ‘example.’. Si intentas referirte a un campo más allá del último, tal como $8 cuando el registro tiene solo 7 campos, obtienes la cadena vacía.

NF, sin el dólar delante, es una variable implícita cuyo valor es el número de campos en el registro actual. $0, lo cual parece un intento de acceder al campo cero, es un caso especial: representa el registro de entrada completo. Esto es lo que usarías cuando no estuvieses interesado en campos. Aquí están algunos ejemplos más:

awk '$1 ~ /foo/ { print $0 }' Lista–BBS

Este ejemplo imprime cada registro del fichero ‘Lista–BBS’ cuyo primer campo contiene la cadena ‘foo’. El operador ‘~’ se le llama operador de encaje, búsqueda o matching (Ver la sección Expresiones de Comparación); chequea si una cadena (aquí, el campo $1) encaja con una expresión regular dada. En contraste, el siguiente ejemplo:

awk '/foo/ { print $1, $NF }' Lista–BBS

busca ‘foo’ en el registro completo e imprime el primer y el último campo de cada registro de entrada que contenga el patrón ‘foo’.

Referenciar campos sin usar constantes

El número de un campo no necesita ser una constante. Cualquier expresión del lenguaje awk puede ser usado después de un ‘$’ para referirse a un campo. El valor de la expresión especifica el número de campo. Si el valor es una cadena, en lugar de un número, dicha cadena se convierte a número. Considere este ejemplo:

awk '{ print $NR }'

Recuerde que NR es el número de registros leídos hasta el momento: 1 para el primer registro, 2 para el segundo, etc. Así que este ejemplo imprimiría el primer campo del primer registro, el segundo campo del segundo registro, y así sucesivamente. Para el registro veinte, se imprimiría el campo número 20; es probable que el registro tenga menos de 20 campos, así que imprimiría una línea en blanco.

Aquí tienes otro ejemplo de la utilización de una expresión como número de campo:

awk '{ print $(2*2) }' Lista–BBS

El lenguaje awk debe evaluar la expresión (2*2) y usar su valor como el número del campo a imprimir. El signo ‘*’ representa multiplicación, así que la expresión 2*2 toma el valor 4. Los paréntesis son usados para que la multiplicación se realice antes que la operación ‘$’; son necesarios donde quiera que haya un operación binario en la expresión número de campo. Este ejemplo, entonces, imprime las horas de operación (el cuarto campo) para cada línea del fichero ‘Lista–BBS’.

Si el número de campo toma el valor de 0, obtienes el registro entero. Por lo que, $(2-2) tiene el mismo valor que $0. Números de campo negativos no son permitidos.

El número de campos en el registro actual se almacena en la variable implícita NF (Ver la sección 12. Variables Implícitas (Built-in). La expresión $NF no es una característica especial: es la consecuencia directa de evaluar NF y usar su valor como número de campo.

Cambiando los contenidos de un campo

Puedes cambiar los contenidos de un campo dentro de un programa awk; estos cambios que awk percibe como el registro de entrada actual (La entrada real es intocable: awk nunca modifica el fichero de entrada). Mire este ejemplo:

awk '{ $3 = $2 - 10; print $2, $3 }' inventario–enviado

El signo ‘-’ representa la substracción, de modo que este programa reasigna el campo tres, $3, y le da el valor del campo 2 menos el campo décimo, $2 - $10. (Ver la sección Operadores Aritméticos). El campo dos, y el nuevo valor del campo tres son impresos.

Para poder realizar esta operación, el texto del campo dos debe ser susceptible a ser convertido a número, la cadena de caracteres debe ser convertida a número para que se puede realizar la operación aritmética sobre dicho campo. El número resultante de la sustracción se convierte de nuevo a cadena de caracteres cuando se convierte en el campo tercero. Ver la sección Conversiones de Cadenas y Números.

Cuando cambias el valor de un campo (como es percibido por awk), el texto del registro de entrada es recalculado para contener el nuevo campo en la posición en la que estaba el antiguo. Por lo tanto, $0 cambia para reflejar el campo alterado. Por lo que,

awk '{ $2 = $2 - 10; print $0 }' inventario–enviado

imprime una copia del fichero de entrada, restándole 10 unidades a cada uno de los valores que presenta el campo 2 para todas las líneas.

También puedes asignar contenidos a campos que están fuera del rango. Por ejemplo:

awk '{ $6 = ($5 + $4 + $3 + $2) ; print $6 }' inventario–enviado

Acabamos de crear el campo $6, cuyo valor es la suma de los campos $2, $3, $4, y $5. El signo ‘+’ representa la suma. Para el fichero ‘inventario–enviado’, $6 representa el número total de objetos embarcados para un mes en particular.

La creación de un nuevo campo cambia la copia interna del registro de entrada actual que tiene awk – el valor de $0. Por lo que, si realiza un ‘print $0’ después de añadir un campo, el registro impreso incluye el nuevo campo, con el número de separadores de campo apropiado entre el nuevo campo y los campos existentes previamente.

Esta recomputación afecta y se ve afectada por varias características todavía no discutidas, en particular, el separador de campos de salida, OFS, que se usa para separar los campos (Ver la sección Separadores de la Salida), y NF (el número de campos; Ver la sección Examinando campos). Por ejemplo, el valor de NF se fija al número del campo mayor que hayas creado.

Anotar, sin embargo, que referenciar a un campo fuera de rango no cambia ni el valor de $0 ni el de NF. El referenciar a un campo fuera de rango produce simplemente una cadena nula. Por ejemplo:

if ($(NF+1) != "")

    print "no puede ocurrir"

else

    print "todo es normal"

imprimiría `todo es normal', ya que NF+1 está fuera de rango ciertamente (Ver la sección La Sentencia if, para más información sobre las sentencias de awk if-else).

Especificando como están separados los campos

El modo en el que awk divide los registros de entrada en campos es controlada por el separador de campo, el cual es un carácter simple o una expresión regular. Awk recorre el registro de entrada en búsqueda de coincidencias del separador de campos; los campos son el texto que se encuentra entre dichos separadores de campos encontrados. Por ejemplo, si el separador de campos es ‘oo’, entonces la siguiente línea:

moo goo gai pan

será particionada en tres campos: `m', ` g' y ` gai pan'.

El separador de campos está representado por la variable implícita FS. ¡Que tomen nota los programadores de la Shell! Awk no usa el nombre IFS el cual es usado por la shell. Puedes cambiar el valor de FS en el programa awk con el operador asignación, ‘=’ (Ver la sección Expresiones de Asignación). A menudo el momento adecuado para hacer esto es el principio de la ejecución, antes de que se procese ninguna entrada, de forma que el primer registro se lea con el separador adecuado. Para hacer esto, use el patrón especial BEGIN (Ver la sección Los Patrones Especiales BEGIN y END). Por ejemplo, aquí hemos fijado el valor de la variable FS a la cadena “,”:

awk 'BEGIN { FS = "," } ; { print $2 }'

Dada la siguiente línea,

John Q. Smith, 29 Oak St., Walamazoo, MI 42139

Este programa awk extrae la cadena `29 Oak St.'.

Algunas veces tus datos de entrada contendrán caracteres separadores que no separen los campos de la forma que tu pensabas que debieran estar separados. Por ejemplo, los nombres de personas en el ejemplo que hemos estado usando podría tener un título o sufijo acoplado, tal como `John Q. Smith, LXIX'. Para la entrada que contuviese dicho nombre:

John Q. Smith, LXIX, 29 Oak St., Walamazoo, MI 42139

El programa de ejemplo anterior extraería `LXIX', en lugar de `29 Oak St.'. Si estabas esperando que el programa escribiese la dirección, serías sorprendido. Así que elige la disposición de tus datos y separadores de campos cuidadosamente para prevenir tales problemas.

Como ya sabes, por defecto, los campos son separados por secuencias de espacios en blanco (espacios y tabuladores), no por espacios simples: dos espacios en una fila no delimitan un campo vacío. El valor por defecto del separador de campos es una cadena “ ” que contiene un único espacio. Si este valor fuese interpretado de la forma usual, cada carácter espacio separaría campos, de forma que dos espacios en una fila crearían un campos vacío entre ellos. La razón por lo que esto no ocurre es porque un espacio simple como valor de FS es un caso especial: se toma para especificar la manera por defecto de deliminar campos.

Si FS es cualquier otro carácter simple, tal y como “,”, cada ocurrencia de dicho carácter separa dos campos. Dos ocurrencias consecutivas delimitan un campo vacío. Si el carácter ocurre al comienzo o al final de la línea, eso también  delimita un campo vacío. El carácter espacio es el único carácter que no sigue estas reglas.

Más generalmente, el valor de FS podría ser una cadena que contuviese una expresión regular. Entonces cada coincidencia en el registro de la expresión regular separa campos. Por ejemplo, la asignación:

FS = ", \t"

hace que cada área de una línea de entrada que consista en una coma seguida de un espacio y un tabulador sea un separador de campo (‘\t’ representa el tabulador).

Para un ejemplo menos trivial de una expresión regular, supón que deseas que los espacios simples separen los campos de la misma forma que lo harían unas comas si fuesen usadas. Le podrías asignar a FS el valor “[ ]”. Esta expresión regular concuerda con un único espacio y nada más.

El valor de FS puede ser fijado en la línea de comando. Use el argumento ‘-F’ para hacerlo. Por ejemplo:

awk -F, 'program' input-files

fija FS para que sea el carácter ‘,’. Dese cuenta de que el argumento aparece en mayúsculas ‘-F’. Esto contrasta con ‘-f’, el cual especifica un fichero que contiene un programa awk. La distinción entre mayúsculas y minúsculas es significativa en las opciones de comando: las opciones ‘-F’ y ‘-f’ no tienen nada que ver la una con la otra. Puedes usar ambas opciones al mismo tiempo para fijar el argumento FS y para decirle a awk que el programa se encuentra en un determinado fichero.

Un caso especial, en modo compatibilidad (Ver la sección 14. Invocación de awk), si el argumento a ‘-F’ es ‘t’, entonces el FS es fijado al carácter tabulador. (Esto es porque si tú tecleas ‘-F\t’, sin las comillas, en el shell, el carácter ‘\’ es eliminado, de forma que awk supone que tú realmente quieres que tus campos estén separados por tabuladores, y no por t’s. Use ‘FS=“T”’ en la línea de comando si deseas realmente que tus campos aparezcan separados por t’s.)

Por ejemplo, utilicemos un fichero de programa awk llamado ‘baud.awk’ que contiene el patrón /300/, y la acción ‘print $1’. Aquí se presenta el programa:

/300/   { print $1 }

Fijemos también el valor de FS al carácter ‘-’, y ejecute el programa sobre el fichero ‘Lista–BBS’ El siguiente comando imprime una lista de los nombres del bulletin boards que operan a 300 baudios y los tres primeros dígitos de sus números de teléfono:

awk -F- -f baud.awk Lista–BBS

Produce la siguiente salida:

aardvark     555

alpo

barfly       555

bites        555

camelot      555

core         555

fooey        555

foot         555

macfoo       555

sdace        555

sabafoo      555

Dese cuenta de la segunda línea de la salida. Si chequeas el fichero original, verás que la segunda línea presenta lo siguiente:

alpo-net     555-3412     2400/1200/300     A

El guíon ‘-’ como parte del nombre del sistema fue utilizado como separador de campo, en lugar del guión que aparecía en el número de teléfono que era lo que se pretendía. Esto te demuestra porqué tienes que ser cuidadoso a la hora de elegir tus separadores de campo y registro.

El siguiente programa busca en el fichero de sistema password, e imprime las entrada de aquellos usuarios que no tiene password:

awk -F: '$2 == ""' /etc/passwd

Aquí usamos la opción ‘-F’ de la línea de comando para fijar el separador de campo. Advierta que los campos en ‘/etc/passwd’ están separados por dos puntos. El segundo campo representa una password de usuario encriptada, pero si el campo está vacío, dicho usuario no tiene password.

Registros de múltiples líneas

En algunas bases de datos, una sola línea no puede guardar convenientemente la información de un registro. En tales casos, puedes usar registros de líneas múltiples.

El primer paso para hacer esto es elegir el formato de tus datos: cuando los registros no vienen definidos como líneas simples, ¿cómo quieres definirlos? ¿qué debería separar los registros?

Una técnica es usar un carácter inusual o cadena para separar los registros. Por ejemplo, podrías usar el carácter formfeed (escrito ‘\f’ en awk, como en C) para separarlos, haciendo que cada registro fuese una página del fichero. Para hacer esto, simplemente fija la variable RS a “\f” (una cadena que contenga el carácter formfeed) Cualquier otro carácter podría ser usado igualmente, siempre y cuando dicho carácter nunca forme parte de los datos posibles de un registro.

Otra técnica es tener registros separados por líneas en blanco. Como dispensación especial, una cadena nula como valor de RS indica que los registros estarán separados por una o más líneas en blanco. Si le das a la variable RS el valor cadena nula, un registro siempre acaba en la primera línea en blanco que encuentra. Y el siguiente registro no comienza hasta que no se encuentra la siguiente línea que no sea una línea en blanco – no importa cuantas líneas en blanco aparezcan en una fila, son consideradas como un único separador de registro.

El segundo paso es separar los campos del registro. Una forma para hacer esto es poner cada campo en una línea por separado: para hacer esto, fija la variable FS a la cadena “\n”. (Esta expresión regular simple concuerda con un simple carácter newline).

Otra idea es dividir cada línea en campos de la forma normal. Esto ocurre por defecto como resultado de una característica especial: cuando RS se fija a la cadena nula, el carácter newline siempre actúa como un separador de campo. Esto es una adición a cuales quiera separaciones de campos resultantes de FS.

Entrada explícita con getline

Hasta ahora hemos estado obteniendo nuestros ficheros de entrada desde el stream de entrada principal de awk – o la entrada estándar (normalmente tu terminal) o los ficheros especificados en la línea de comandos. El Lenguaje awk tiene un comando implícito especial llamado getline que puede ser usado para leer la entrada bajo tu control explícito.

Este comando es bastante complejo y no debería ser usado por principiantes. Se explica aquí porque este es el capítulo de la entrada. Los ejemplos que siguen a la explicación del comando getline incluyen material que no ha sido explicado todavía. Por lo tanto, vuelve a estudiar el comando getline después de haber visto el manual completo y que tengas un buen conocimiento de cómo funciona awk.

El comando getline devuelve un 1 si encuentra un registro, y 0 si se encuentra el final del fichero. Si se produce algún error al obtener un registro, debido por ejemplo a que dicho fichero no pueda ser abierto, entonces getline devolverá un –1.

En los siguientes ejemplos, comando representa una cadena que representa un comando del shell.

Getline

El comando getline puede ser usado sin argumentos para leer la entrada del fichero de entrada actual. Todo lo que hace en este caso es leer el siguiente registro de entrada y dividirlo en campos. Esto es útil cuando has acabado de procesar el registro actual y no vas a realizar ninguna alteración del mismo y quieres procesar justo en ese momento el siguiente registro. Aquí tienes un ejemplo:

awk '{

     if (t = index($0, "/*")) {

          if(t > 1)

               tmp = substr($0, 1, t - 1)

          else

               tmp = ""

          u = index(substr($0, t + 2), "*/")

          while (! u) {

               getline

               t = -1

               u = index($0, "*/")

          }

          if(u <= length($0) - 2)

               $0 = tmp substr($0, t + u + 3)

          else

               $0 = tmp

     }

     print $0

}'

Este programa awk borra todos los comentarios, `/* ... */', de la entrda. Sustituyendo el comando ‘print $0’ con otras sentencias, podrías realizar un procesamiento más complejo sobre la entrada comentada, tal y como buscar si casa con una expresión regular.

Esta forma del comando getline fija el valor de NF (el número de campos; Ver la sección Examinando campos), NR (el número de registros leídos hasta ahora, Ver la sección Cómo se particiona la Entrada en Registros), FNR (el número de registros leídos del fichero de entrada actual), y el valor de $0.

Nota: el nuevo valor de $0 se usa en el chequeo de los patrones de las reglas subsiguientes. El valor original de $0 que disparó la regla que ejecutó getline se pierde. Por contraste, la sentencia next lee un nuevo registro pero inmediatamente comienza a procesarlo normalmente, comenzando con la primera regla del programa. Ver la sección La Sentencia next.

Getline variable

Esta forma de getline lee un registro en la variable variable. Esto es útil cuando quieres que tu programa lea el siguiente registro del fichero de entrada actual, pero no quieres someter el registro que leas al procesamiento de la entrada normal.

Por ejemplo, supón que la siguiente línea es un comentario, o una cadena especial, y quieres leerla, pero quieres realizar lo que sea que no dispare ninguna regla. Esta versión de getline te permite leer esa línea y almacenarla en una variable de forma que el bucle principal de leer una línea y chequearla contra todas las reglas nunca llega a conocer dicha línea.

El siguiente ejemplo alterna (swaps) cada dos líneas de entrada. Por ejemplo, dado:

wan

tew

free

phore

produce la siguiente salida:

tew

wan

phore

free

Aquí tienes el programa:

awk '{

     if ((getline tmp) > 0) {

          print tmp

          print $0

     } else

          print $0

}'

La función getline usada de esta forma fija solamente las variables NR y FNR ( y por supuesto, variable). El registro no es dividido en campos, de forma que los valores de los campos  (incluyendo $0) y el valor de la variable NF no cambia.

getline < fichero

Esta forma de la función getline toma su entrada desde el fichero fichero. Aquí fichero es una expresión que se trata como una cadena que contiene el nombre del fichero. A la expresión ‘<fichero’ se le llama redirección ya que direcciona la entrada para que venga desde un lugar diferente.

Esta forma es útil si quieres leer la entrada de un fichero en particular, en lugar de la stream de entrada principal. Por ejemplo, el siguiente programa lee su registro de entrada del fichero ‘foo.input’ cuando encuentra un primer campo con un valor igual a 10 en el fichero de entrada actual.

awk '{

if ($1 == 10) {

     getline < "foo.input"

     print

} else

     print

}'

Debido a que el stream de entrada principal no se usa, los valores de NR y FNR no se cambian. Pero el registro leído es partido en campos como si fuera un registro normal, por lo que los valores de $0 y otros campos son cambiados. Lo mismo le ocurre al valor de NF. Esto hace que el registro leído no sea chequeado contra todos los patrones del programa awk, del mismo modo que ocurriría si el registro hubiese sido leído normalmente por el bucle principal de proceso de awk. Sin embargo el nuevo registro es chequeado contra las reglas restantes, del mismo modo que ocurría cuando se usaba getline sin la redirección.

getline variable < fichero

Esta forma de la función getline toma su entrada del fichero fichero y la pone en la variable variable. Como anteriormente, fichero es una expresión cuyo valor es una cadena, la cual especifica el fichero del que se va a leer.

En esta versión de getline, ninguna de las variable implícitas cambia su valor, y el registro no es dividido en campos. La única variable que cambia es variable. Por ejemplo, el siguiente programa copia todos los ficheros de entrada a la salida, excepto los registros que dicen `@include nombre_fichero'. Tales registros son reemplazados por el contenido del fichero nombre_fichero.

awk '{

     if (NF == 2 && $1 == "@include") {

          while ((getline line < $2) > 0)

               print line

          close($2)

     } else

          print

}'

Advierta aquí como el nombre del fichero de entrada extra no se construye en el programa; es cogido de los datos, del segundo campo de las líneas ‘@include’.

La función close se llama para asegurarse que si aparecen dos líneas ‘@include’ idénticas, el fichero especificado entero se incluye dos veces. Ver la sección Cerrado de Ficheros de Entrada y Pipes.

Una deficiencia de este programa es que no procesa las sentencias ‘@include’ anidadas del mismo modo que un preprocesador de macros haría.

comando ¦ getline

Puedes hacer un pipe de la salida a un comando a getline. Un pipe es simplemente una forma de enlazar la salida de un programa con la entrada de otro. En este caso, la cadena comando es ejecutada como un comando de la shell y su salida es pipeada dentro de awk para que sea usado como entrada. Esta forma de getline lee un registro del pipe.

Por ejemplo, el siguiente programa copia la entrada a la salida, excepto las líneas que comienzan con ‘@execute’, las cuales son reemplazadas por la salida producida por la ejecución del resto de la línea como un comando de shell:

awk '{

     if ($1 == "@execute") {

          tmp = substr($0, 10)

          while ((tmp ¦ getline) > 0)

               print

          close(tmp)

     } else

          print

}'

La función close se usa para asegurarse de que si aparecen dos líneas ‘@execute’ idénticas, el comando se ejecute de nuevo para cada línea. Ver la sección Cerrado de Ficheros de Entrada y Pipes.

Dada la siguiente entrada:

foo

bar

baz

@execute who

bletch

el programa podría producir:

foo

bar

baz

hack     ttyv0   Jul 13 14:22

hack     ttyp0   Jul 13 14:23     (gnu:0)

hack     ttyp1   Jul 13 14:23     (gnu:0)

hack     ttyp2   Jul 13 14:23     (gnu:0)

hack     ttyp3   Jul 13 14:23     (gnu:0)

bletch

Dese cuenta de que este programa ejecutó el comando who e imprimió el resultado.

Esta variación de getline divide el registro en campos, fija el valor de NF y recalcula el valor de $0. Los valores de NR y FNR no son cambiados.

comando ¦ getline variable

La salida del comando comando se envía a través de un pipe a getline y a la variable variable. Por ejemplo, el siguiente programa lee la hora y día actual a la variable tiempo_actual, usando la utilidad llamada date, y después la imprime.

awk 'BEGIN {

     "date" ¦ getline tiempo_actual

     close("date")

     print "Report printed on " tiempo_actual

}'

En esta versión de getline, ninguna de las variable implícitas es cambiada, y el registro no se divide en campos.

Cerrado de Ficheros de Entrada y Pipes

Si se usa el mismo nombre de fichero o el mismo comando shell se usa con getline más de una vez durante la ejecución de un programa awk, el fichero es abierto (o el comando es ejecutado) sólo la primera vez. En ese momento, el primer registro de la entrada es leído de ese fichero o comando. La próxima vez que se use ese mismo nombre de fichero o comando con getline, otro registro se leerá de él, y así sucesivamente.

Esto implica que si quieres comenzar la lectura del mismo fichero desde el principio, o si quieres volver a ejecutar un comando (en lugar de leer más salida del comando), debes realizar unos pasos especiales. Lo que puedes usar es la función close, tal y como sigue:

close(fichero)

o

close(comando)

El argumento fichero o comando puede ser cualquier expresión. Su valor debe ser exactamente el mismo que la cadena que fue usada para abrir el fichero o comenzar el comando – por ejemplo, si abres un pipe con esto:

"sort -r names" ¦ getline foo

entonces debes cerrar el pipe de esta forma:

close("sort -r names")

Una vez que se ejecuta esta llamada a la función, el siguiente getline de ese fichero o comando reabrirá el fichero o reejecutará el comando.

   
Índice
Manual