Las sentencias de control tales como if, while, y así
sucesivamente controlan el flujo de la ejecución de los programas awk. La mayoría de las sentencias
de control de awk son similares a sus sentencias análogas en Lenguaje
C.
Todas las sentencias de control comienzan con las palabras claves tales como if y while, para
distinguirlas de las expresiones simples.
Muchas sentencias de control contienen otras
sentencias; por ejemplo, la sentencia if contiene otra sentencia la cual podría
ser ejecutada o no. Las sentencias contenidas se llaman el cuerpo.
Si quieres incluir más de una sentencia en el cuerpo, agrupalas en una única
sentencia compuesta con llaves, separándose entre ellas con puntos y comas y
saltos de línea.
La sentencia ifelse es una sentencia para la toma de decisiones
de awk.
Presenta la siguiente forma:
if (condición) cuerpothen [else cuerpoelse]
Aquí condición es una expresión que controla qué es lo que realizará el resto de la
sentencia. Si la condición es verdad, entonces se ejecuta el cuerpothen; sino se ejecuta el cuerpoelse (asumiendo que esté presente la clásula else). La parte else de la sentencia es opcional. La condición
se considera falsa si su valor es 0 o una cadena nula, sino se considerará verdadera.
Aquí se presenta un ejemplo:
if (x % 2 == 0)
print "x es par"
else
print "x es impar"
En este ejemplo, si la expresión x%2 == 0 es cierta
(es decir, el valor de x es divisible entre 2), entonces se ejecuta la primera
sentencia print, sino se ejecuta la segunda sentencia print.
Si el else aparece en la misma línea que el
cuerpothen, y el cuerpothen no es una sentencia compuesta (no
aparece entre llaves), entonces un punto y coma debe separar el cuerpothen
del else. Para ilustrar esto veamos el siguiente ejemplo:
awk '{ if (x % 2 == 0) print "x is even"; else
print "x is odd" }'
Si olvidas el ; awk no será capaz de realizar el parse de la sentencia, y obtendrás un error
de sintáxis. De todas formas es una mala práctica escribir la sentencia else
de esta forma, ya que puede llevar al lector a confusión.
En programación, un bucle significa una parte
de programa que es (o al menos puede ser) ejecutada dos o más veces seguidas.
La sentencia while es la sentencia de bucle
más simple de awk. Ejecuta repetidamente una sentencia mientras una condición sea cierta.
Presenta la siguiente forma:
while (condición)
cuerpo
Aquí cuerpo es una sentencia a la que llamamos
el cuerpo del bucle, y condición es una expresión que controla
cuantas veces se ejecuta dicho cuerpo.
La primera cosa que hace la sentencia while
es comprobar la condición. Si condición es cierta, ejecuta la
sentencia cuerpo. (Verdad, como es usual en awk, significa que el valor de la condición es distinto de cero y
la cadena nula). Después de que el cuerpo se haya ejecutado, se chequea
la condición de nuevo, y si sigue siendo cierta, el cuerpo se
ejecuta de nuevo. Este proceso se repite hasta que la condición deja
de ser cierta. Si la condición es falsa inicialmente, el cuerpo del bucle
nunca es ejecutado.
Este ejemplo imprime los tres primeros campos de cada
registro, uno por línea.
awk '{ i = 1
while (i <= 3) {
print $i
i++
}
}'
Aquí el cuerpo del bucle es una sentencia compuesta
encerrada entre llaves, que contiene dos sentencias.
El bucle trabaja de la siguiente forma: primero, el
valor de i es fijado a 1. Entonces, el while chequea si i es menor o
igual a tres. Este es el caso cuando i es igual a uno, así que el campo
iésimo es impreso. Entonces el comando i++ incrementa el valor de i y se repite
el bucle. El bucle termina cuando i alcanza el valor de 4.
Como puedes comprobar, un carácter de nueva línea
no es requerida entre la condición y el cuerpo; pero usándola hace que el programa
sea más claro a menos que el cuerpo sea una sentencia compuesta o una muy simple.
El carácter newline después de la llave de apertura que inicia la sentencia
compuesta no es obligatoria, pero el programa será menos legible sino se pone.
El bucle do es una variación de la sentencia
de bucle while. El bucle do ejecuta el cuerpo al menos
una vez, después repite el cuerpo mientras la condición se siga
evaluando a cierto. Presenta la siguiente forma:
do
cuerpo
while (condición)
Incluso aunque condición sea falsa inicialmente,
el cuerpo se ejecuta al menos una vez (y sólo una vez, a menos que el
cuerpo de ejecución siga haciendo que la condición sea cierta).
Contrasta esto con la correspondiente sentencia while:
while (condición)
cuerpo
Esta sentencia no ejecuta el cuerpo ni una
vez si la condición es falsa antes de empezar.
Aquí está un ejemplo de una sentencia do:
awk '{ i = 1
do {
print $0
i++
} while (i <= 10)
}'
imprime cada registro de entrada 10 veces. No es un ejemplo muy realista, ya que un while ordinario podría haber hecho lo mismo.
La sentencia for es más conveniente para contar
las iteraciones de un bucle. La forma general de la sentencia for presenta
la siguiente forma:
for (inicialización; condición; incremento)
cuerpo
Esta sentencia comienza ejecutando inicialización.
Después, mientras la condición sea cierta, ejecuta repetidamente el cuerpo
y el incremento. Normalmente la inicialización fija el valor de
la variable a 0 o 1, incremento añade 1 a dicho valor, y condición
compara el nuevo valor contra el número de iteraciones deseado.
Aquí tienes un ejemplo de una sentencia for:
awk '{ for (i = 1; i <= 3; i++)
print $i
}'
Esto imprime los tres primers campos de cada registros de entrada, un campo por línea.
En la sentencia for, el cuerpo está
formado por sentencias, pero inicialización, condición e incremento
son simples expresiones. No puedes fijar el valor de más de una variable en
la parte inicialización a menos que uses una sentencia de asignación
múltiple tal como x = y = z = 0, la cual sólo es posible si todos los valores
iniciales son el mismo (pero puedes inicializar variables adicionales escribiendo
sus asignaciones como sentencias separadas que precedan al bucle for).
Lo mismo se cumple para la parte incremento;
para incrementar variables adicionales, debes escribir sentencias separadas
al final del bucle. La expresión compuesta C, que usa el separador de C coma,
sería útil en este contexto, pero no está soportada por awk.
En la mayoría de los casos, incremento es una
expresión incremental, como en el ejemplo de arriba. Pero esto no es obligatorio;
podría ser cualquier expresión. Por ejemplo, esta sentencia imprime todas las
potencias de 2 entre 1 y 100:
for (i = 1; i <= 100; i *= 2)
print i
Cualquiera de las tres expresiones en los paréntesis que siguen
al for podría ser omitida si no fuese necesaria. Por lo que, for (;x > 0;) es equivalente a while (x > 0). Si la condición se omite,
se trata como cierta, dando lugar a un bucle infinito efectivo.
En la mayoría de los casos, un bucle for es una abreviación de
un bucle while, tal y como se muestra aquí:
inicialización
while (condición) {
cuerpo
incremento
}
La única excepción es cuando se utiliza la sentencia
continue (Ver la sección La
Sentencia continue) dentro del bucle; cambiar una sentencia
for por una sentencia while de esta forma puede cambiar el efecto
de la sentencia continue dentro del bucle.
Existe una versión alternativa del bucle for,
para hacer una iteración para cada índice de un array:
for (i in array)
hacer algo con array[i]
Ver la sección 10. Arrays en awk, para más información de esta versión del bucle for.
El Lenguaje awk tiene una sentencia for además de la sentencia while porque
a menudo un bucle for es más fácil para escribirla y más natural para
pensarla y entenderla. Contar el número de iteraciones es muy común en los bucles.
Es más fácil pensar este conteo como parte del bucle en lugar de cómo algo a
hacer dentro del bucle. La siguiente sección tiene ejemplos más complicados
de bucles for.
La sentencia break se sale del bucle for, while
o dowhile más interno en el que está contenido. El siguiente ejemplo
encuentra el divisor más pequeño de cualquier entero, y también identifica números
primos:
awk '# encuentra el divisor más pequeño de num
{ num = $1
for (div = 2; div*div <= num; div++)
if (num % div == 0)
break
if (num % div == 0)
printf "Smallest divisor of %d is %d\n", num, div
else
printf "%d is prime\n", num }'
Cuando el resto es cero en la primera sentencia if, awk se sale inmediatamente del bucle for en el que
está contenido. Esto significa que awk procede inmediatamente a la sentencia que sigue al bucle y continúa el
procesamiento. (Esto es muy distinto de la sentencia exit (ver la sección
La
Sentencia exit) la cual detiene el programa awk completo.)
Aquí está otro programa equivalente al anterior. Ilusta
como la condición de un for o while podría simplemente
ser substituida con un break dentro de un if:
awk '# find smallest divisor of num
{ num = $1
for (div = 2; ; div++) {
if (num % div == 0) {
printf "Smallest divisor of %d is %d\n", num, div
break
}
if (div*div > num) {
printf "%d is prime\n", num
break
}
}
}'
La sentencia continue, al igual que break,
se usa solamente dentro de un bucle for, while o dowhile. Lo
que hace es saltarse todas las sentencias que falten por ejecutarse dentro del
cuerpo del bucle y volver a chequear automáticamente la condición del bucle.
Contrasta con la sentencia break, en que ésta produce directamente un salto
fuera del bucle. Aquí se presenta un ejemplo:
# print names that don't contain the string "ignore"
# first, save the text of each line
{ names[NR] = $0 }
# print what we're interested in
END {
for (x in names) {
if (names[x] ~ /ignore/)
continue
print names[x]
}
}
Si uno de los registros de entrada contiene la cadena
ignore, este ejemplo se salta la sentencia print para ese registro, y vuelve
a la primera sentencia del bucle.
Este no es un ejemplo práctico de continue,
ya que está sería una forma más sencilla de escribir el bucle:
for (x in names)
if (names[x] !~ /ignore/)
print names[x]
La sentencia continue en un bucle for hace que awk
se salte el resto del cuerpo del bucle, y resume la ejecución con la expresión
incremento de la sentencia for. El siguiente programa ilustra esto de
hecho:
awk 'BEGIN {
for (x = 0; x <= 20; x++) {
if (x == 5)
continue
printf ("%d ", x)
}
print ""
}'
Este programa imprime todos los números de 0 a 20,
excepto el 5 para el cual se salta el print. Ya que el incremento no es saltado,
x no permanece estancado en 5. Contrasta el bucle for de arriba con el
bucle while:
awk 'BEGIN {
x = 0
while (x <= 20) {
if (x == 5)
continue
printf ("%d ", x)
x++
}
print ""
}'
Este programa se convierte en un bucle infinito una vez que x
alcanza el valor de 5.
La sentencia next fuerza a awk que detenga inmediatamente el procesamiento del registro
actual y vaya a leer el siguiente registro. Esto significa que no se ejecutará
ninguna regla más para el registro en curso. El resto de las acciones de la
regla actual no se ejecutarán.
Contrasta esto con el efecto de la función getline
(Ver la sección Entrada
explícita con getline). Eso también hace que awk lea el siguiente registro inmediatamento, pero no se altera el control
de flujo del programa. De forma que el resto de la acción actual se ejecuta
con un nuevo registro de entrada.
En el nivel más alto, la ejecución de un programa
awk es un bucle que lee un registro de entrada y entonces
lo chequea contra el patrón de cada regla. Si piensas en este bucle como una
sentencia for cuyo cuerpo contiene reglas, entonces la sentencia next
es análoga a una sentencia continue: se salta el resto del cuerpo de
este bucle implícito, y ejecuta el imcremento (lo que provoca la lecuta de otro
registro).
Por ejemplo, si tu programa awk trabaja sólo sobre registros con cuatro campos, y no quieres que procese
una entrada incorrecta, podrías usar esta regla cerca del principio del programa:
NF != 4 {
printf("line %d skipped: doesn't have 4 fields", FNR) > "/dev/stderr"
next
}
de forma que las reglas siguientes no verán el registro incorrecto. El mensaje de error se redirecciona al streem de salida de error estándar, como debiera ser para los mensajes de error. Ver la sección Streams de Entrada/Salida Estándard.
La sentencia next no está permitida en una
regla BEGIN o END.
La sentencia exit hace que awk detenga la ejecución de la regla actual inmediatamente
y detenga el procesamiento de la entrada, cualquier registro que falte es ignorado.
Si una sentencia exit se ejecuta en una regla
BEGIN el programa detiene el procesamiento de todo inmediatamente. No se leería
ningún registro de entrada. Sin embargo, si existe una regla END, ésta es ejecutada (Ver la sección Los
Patrones Especiales BEGIN y END).
Si se usa exit como parte de una regla END, hace que el programa se
detenga inmediatamente.
Una sentencia exit como parte de una regla
ordinaria (esto es, no forme parte de una regla BEGIN y END) detiene la ejecución de
cualquier regla automática posterior, pero la regla END sí es ejecutada si existe. Si no quieres que la regla END realice su trabajo en estos casos, puedes fijar una variable a distinto
de cero antes de la sentencia exit, y chequear dicha variable en la regla
END.
Si se le suministra un argumento a exit, su
valor se usa como el código de estado de salida para el proceso awk. Si no se le suministra argumento, exit devuelve
el estado 0 (éxito). Por ejemplo, digamos que has descubierto una condición
de error que no sabes como manejar realmente. Convencionalmente, el programa
te reporta esto saliéndose con un estado distinto de cero. Tu programa awk
puede hacer esto usando una sentencia exit con un argumento distinto
de cero. Aquí tienes un ejemplo de esto:
BEGIN {
if (("date" ¦ getline date_now) < 0) {
print "Can't get system date" > "/dev/stderr"
exit 4
}
}
Manual |