Entrada explícita con getline AWK

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. Los ejemplos que siguen a la explicación del comando getline incluyen material que no ha sido explicado todavía. 

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, NR (el número de registros leídos hasta ahora), 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 ‘

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.

Publicar un comentario

0 Comentarios