Documentos de Académico
Documentos de Profesional
Documentos de Cultura
9 Sed&Awk - En.es
9 Sed&Awk - En.es
En este capítulo:
• Funciones aritméticas
• Funciones de cuerda
• Escribiendo tus propias funciones
9
Las
funciones
Una función es un cálculo autónomo que acepta una serie de argumentos como entrada y
devuelve algún valor. Awk tiene varias funciones integradas en dos grupos: funciones
aritméticas y de cadena. Awk también proporciona funciones definidas por el usuario,
que le permiten ampliar las funciones integradas escribiendo las suyas propias.
Funciones aritméticas
Nueve de las funciones integradas se pueden clasificar como funciones aritméticas. La
mayoría de ellos toman un argumento numérico y devuelven un valor numérico. La tabla
9-1 resume estas funciones aritméticas.
Tabla 9−1: Funciones aritméticas integradas de awk
203
204 204 Capítulo 9: Funciones
Funciones trigonométricas
Las funciones trigonométricas cos () y sin () funcionan de la misma manera, tomando un
solo argumento que es el tamaño de un ángulo en radianes y devolviendo el coseno o
seno para ese ángulo. (Para convertir de grados a radianes, multiplique el número por π/
180.) La función trigonométrica atan2 () toma dos argumentos y devuelve el arcotangente
de su cociente. La expresion
atan2 (0, -1)
productos π.
devuelve el número natural 2.71828, la base de los logaritmos naturales, referido como e.
Por lo tanto, exp (x) es e para la x-ésima potencia.
Función entera
La función int () trunca un valor numérico eliminando dígitos a la derecha del punto
decimal. Mira las siguientes dos declaraciones:
imprimir 100/3
print int (100/3)
La función int () simplemente se trunca; No se redondea hacia arriba o hacia abajo. (Use
**
pr intf para el tapete "% .0f" para realizar el redondeo).
* La forma en que pr intf realiza el redondeo se analiza en el Apéndice B, Referencia rápida para awk.
Funciones aritméticas 205
Si no llama a srand () en absoluto, awk actúa como si se hubiera llamado a srand () con
un argumento constante antes de que comenzara su programa, lo que hace que obtenga el
mismo punto de partida cada vez que ejecuta su programa. Esto es útil si desea un
comportamiento reproducible para las pruebas, pero es inapropiado si realmente desea
que su programa se comporte de manera diferente cada vez. Mira el siguiente script:
# rand.awk - prueba de generación de números aleatorios
EMPEZAR {
print rand ()
print rand ()
srand () print
rand () print
rand ()
}
$ awk -f rand.awk
0.513871
0.175726
0.760277
0.263863
Se generan cuatro números aleatorios. Ahora mira lo que sucede cuando volvemos a
ejecutar el programa:
$ awk -f rand.awk
0.513871
0.175726
0,787988
0,305033
Los primeros dos números "aleatorios" son idénticos a los números generados en la
ejecución anterior del programa, mientras que los dos últimos números son diferentes.
Los dos últimos números son diferentes porque proporcionamos la función rand () con
una nueva semilla.
El valor devuelto de la función srand () es la semilla que estaba usando. Esto se puede
utilizar para realizar un seguimiento de las secuencias de números aleatorios y volver a
ejecutarlas si es necesario.
Recogerlos
Para mostrar cómo usar rand (), veremos un script que implementa una "selección rápida"
para un juego de lotería. Este script, llamado lotto, selecciona x números de una serie de
números del 1 al y. Se pueden proporcionar dos argumentos en la línea de comando:
cuántos números elegir (el valor predeterminado es 6) y el número más alto de la serie (el
valor predeterminado
206 Capítulo 9: Funciones
es 30) Usando los valores predeterminados para x e y, el script genera seis números
aleatorios únicos entre 1 y 30. Los números se ordenan por legibilidad de menor a mayor
y de salida. Antes de mirar el script en sí, ejecutemos el programa:
$ loto Elige 6 de 30
91325282930
$ lotto 7 35 Escoge 7 de 35
16916202227
El primer ejemplo utiliza los valores predeterminados para imprimir seis números
aleatorios del 1 al 30. El segundo ejemplo imprime siete números aleatorios de 35.
El script de lotería completo es bastante complicado, así que antes de ver el script
completo, veamos un script más pequeño que genera un solo número aleatorio en una
serie:
awk -v TOPNUM = $ 1 '
# pick1: elige un número aleatorio de y
# rutina principal
EMPEZAR {
# número aleatorio inicial utilizando la hora del día srand ()
Puede ser útil ver esta expresión dividida para que cada parte sea obvia.
Declaración Resultado
imprimir r = rand () 0.467315
imprimir r * TOPNUM 14.0195
print int (r * TOPNUM) 14
print 1 + int (r * TOPNUM) 15
es necesario porque rand () podría devolver n 0. En este ejemplo, el número aleatorio que
se genera es 15. Puede usar este programa para imprimir cualquier número individual,
como elegir un número entre 1 y 100.
$ pick1 100 83
El script de lotería debe "elegir uno" varias veces. Básicamente, necesitamos configurar
un bucle for para ejecutar la función rand () tantas veces como sea necesario. Una de las
razones por las que esto es difícil es que tenemos que preocuparnos por los duplicados.
En otras palabras, es posible que un número sea elegido nuevamente; Por lo tanto,
tenemos que hacer un seguimiento de los números ya seleccionados.
NUM = 6
si (TOPNUM <= 0)
TOPNUM = 30
# imprime "Elige x de y"
printf ("Elija% d de% d \ n", NUM, TOPNUM)
# número aleatorio de semillas usando hora y fecha; haz esto una vez srand ()
A diferencia del programa anterior, este busca dos argumentos de línea de comandos,
indicando x números de y. La rutina principal busca ver si se proporcionaron estos
números y, si no, asigna valores predeterminados.
Hay solo una matriz, pick, para mantener los números aleatorios que están seleccionados.
Se garantiza que cada número está en el rango deseado, porque el resultado de rand ()
208 Capítulo 9: Funciones
(un valor entre 0 y 1) se multiplica por TOPNUM y luego se trunca. El corazón del script
es un bucle que ocurre NUM veces para asignar NUM elementos a la matriz de selección.
Para obtener un nuevo número aleatorio no duplicado, utilizamos un bucle interno que
genera selecciones y pruebas para ver si están en la matriz de selección. (El uso del
operador in es mucho más rápido que recorrer los subíndices de comparación de la
matriz). Mientras (select in pick), el elemento correspondiente ya se ha encontrado, por lo
que la selección es un duplicado y rechazamos la selección. Si no es cierto que select in
pick, entonces asignamos select a un elemento de la matriz pick. Esto hará que el futuro
de las pruebas vuelva a ser verdadero, lo que hará que el ciclo do continúe.
$ lotto 7 35 Escoge 7 de 35
52193029202
Así es, los números no están ordenados. Diferiremos mostrar el código para la rutina de
clasificación hasta que discutamos las funciones definidas por el usuario. Si bien no es
necesario haber escrito el código de clasificación como una función, tiene mucho sentido.
Una razón es que puede abordar un problema más generalizado y conservar la solución
para usarla en otros programas. Más adelante, escribiremos una función que clasifique los
elementos de una matriz.
Tenga en cuenta que la matriz de selección no está lista para ordenar, ya que sus índices
son los mismos que sus valores, no los números en orden. Tendríamos que configurar una
matriz separada para ordenar por nuestra función de clasificación:
Funciones de cuerda
Las funciones de cadena incorporadas son mucho más significativas e interesantes que las
funciones numéricas. Debido a que awk está diseñado esencialmente como un lenguaje
de procesamiento de cadenas, gran parte de su poder deriva de estas funciones. La Tabla
9-2 enumera las funciones de cadena que se encuentran en awk.
Funciones de cuerda 209
La función spr intf () usa las mismas especificaciones de formato que pr intf (), que se
discute en el Capítulo 7, Escritura de scripts para awk. Le permite aplicar las
especificaciones de formato en una cadena. En lugar de imprimir el resultado, spr intf ()
devuelve una cadena que puede asignarse a una variable. Puede realizar un
procesamiento especializado de registros o campos de entrada, como realizar
conversiones de caracteres. Por ejemplo, el siguiente ejemplo usa la función spr intf ()
para convertir un número en un carácter ASCII.
para (i = 97; i <= 122; ++ i) {
nextletter = sprintf ("% c", i)
...
}
Eso nos deja con tres funciones básicas de cadena incorporadas para analizar: index (),
substr () y length ().
Substr ings
Las funciones index () y substr () se ocupan de subcadenas. Dada una cadena s, el índice
(s, t) devuelve n la posición más a la izquierda donde se encuentra la cadena t en s. El
comienzo de la cadena es la posición 1 (que es diferente del lenguaje C, donde el primer
carácter de una cadena está en la posición 0). Mira el siguiente ejemplo:
pos = index ("Mississippi", "es")
Dada una cadena s, substr (s, p) devuelve los caracteres que comienzan en la posición p.
El siguiente ejemplo crea un número de teléfono sin un código de área.
teléfono = substr ("707-555-1111", 5)
Las dos funciones pueden ser y, a menudo, se usan juntas, como en el siguiente ejemplo.
Este ejemplo escribe en mayúscula la primera letra de la primera palabra para cada registro
de entrada.
Este script crea dos variables, superior e inferior, que consisten en letras mayúsculas y
minúsculas. Cualquier personaje que encontremos en la parte inferior se puede encontrar
en la misma posición en la parte superior. La primera declaración del procedimiento
principal extrae una sola
Funciones de cuerda 211
personaje, el primero, del primer campo. La instrucción condicional prueba para ver si
ese carácter se puede encontrar en menor usando la función index (). Si CHAR no es 0,
entonces CHAR puede usarse para extraer el carácter en mayúscula de mayúscula. Hay
dos llamadas de función substr (): la primera recupera la letra mayúscula y la segunda
llamada obtiene el resto del primer campo, extrayendo todos los caracteres, comenzando
con el segundo carácter. Los valores devueltos por ambas funciones substr () se
concatenan y asignan a $ 1. Hacer una asignación a un campo como lo hacemos aquí es
un nuevo giro, pero tiene el beneficio adicional de que el registro se puede generar
normalmente. (Si la asignación se realizó a una variable, tendría que generar la variable y
luego generar los campos restantes del registro). La instrucción pr int imprime el registro
modificado.
Tom
Tom
En un momento, veremos cómo revisar este programa para cambiar todos los caracteres
de una cadena de minúsculas a mayúsculas o viceversa.
Longitud de la cuerda
Al presentar el programa awkro en el capítulo anterior, notamos que era probable que el
programa produjera líneas que superaran los 80 caracteres. Después de todo, las
descripciones son bastante largas. Podemos averiguar cuántos caracteres hay en una
cadena utilizando la función incorporada length (). Por ejemplo, para evaluar la longitud
del registro de entrada actual, especificamos la longitud ($ 0). (Como sucede, si se llama
a length () sin un argumento, devuelve la longitud de $ 0).
La función length () se usa a menudo para encontrar la longitud del registro de entrada
actual, para determinar si necesitamos romper la línea.
Una forma de manejar el salto de línea, quizás de manera más eficiente, es usar la función
length () para obtener la longitud de cada campo. Al acumular esas longitudes, podríamos
especificar un salto de línea cuando un nuevo campo hace que el total exceda un cierto
número.
Funciones de sustitución
Awk proporciona dos funciones de sustitución: sub () y gsub (). La diferencia entre ellos
es que gsub () per forma su sustitución globalmente en la cadena de entrada donde eas
sub () solo realiza la primera sustitución posible. Esto hace que gsub () sea equivalente al
comando de sustitución de sed con el indicador g (global).
Ambas funciones toman al menos dos argumentos. La primera es una expresión regular
(rodeada por barras) que coincide con un patrón y el segundo argumento es una cadena
que reemplaza lo que coincide con el patrón. La expresión regular puede ser suministrada
por una variable, en cuyo caso se omiten las barras. Un tercer argumento opcional
especifica la cadena que es el objetivo de la sustitución. Si no hay un tercer argumento, la
sustitución se realiza para el registro de entrada actual ($ 0).
Por ejemplo, el siguiente ejemplo usa gsub () para reemplazar todas las apariciones de
"UNIX" con "POSIX".
if (gsub (/ UNIX /, "POSIX"))
impresión
Al igual que con sed, si aparece un "&" en la cadena de sustitución, será reemplazado por
la cadena que coincide con la expresión regular. Use "\ &" para generar un ampersand.
(Recuerde que para obtener un literal "\" en una cadena, debe escribir dos de ellos.)
Además, tenga en cuenta que awk no "recuerda" la expresión regular anterior, como lo
hace sed, por lo que no puede usar la sintaxis "/ / "Para referirse a la última expresión
regular.
El siguiente ejemplo rodea cualquier aparición de "UNIX" con las secuencias de escape
trof f-change-change.
gsub (/ UNIX /, "\\ fB & \\ fR")
sed -n '
s / "// g
s / ˆ \ .Se / Capítulo / p
Funciones de cuerda 213
s / ˆ \ .Ah / • A. /pags
s / ˆ \ .Bh /••B./p '$ *
Ahora aquí está ese script reescrito usando las funciones de sustitución:
awk '
{
gsub (/ "/," ")
if (sub (/ˆ\.Se /, "Chapter")) print
if (sub (/ˆ\.Ah /, "\ tA.")) imprimir
if (sub (/ˆ\.Bh /, "\ t \ tB.")) imprimir
PS
Los dos scripts son exactamente equivalentes, imprimiendo solo aquellas líneas que se
cambian. Para la primera edición de este libro, Dale comparó el tiempo de ejecución de
ambos guiones y, como esperaba, el guión awk fue más lento. Para la segunda edición,
los nuevos tiempos mostraron que el rendimiento varía según la implementación, y de
hecho, ¡todas las versiones probadas del nuevo awk fueron más rápidas que sed! Esto es
bueno, ya que tenemos las capacidades en awk para hacer que el script haga más cosas.
Por ejemplo, en lugar de usar letras del alfabeto, podríamos numerar los encabezados.
Aquí está el script awk revisado:
El número de capítulo se lee como el primer argumento de la macro ".Se" y, por lo tanto,
es el segundo campo en esa línea. El esquema de numeración se realiza incrementando
una variable cada vez que se realiza la sustitución. La acción asociada con el encabezado
de nivel de capítulo inicializa los contadores de encabezado de sección a cero. La acción
asociada con el encabezado de nivel superior ".Ah" pone a cero el contador de
encabezado de segundo nivel. Obviamente, puede crear tantos niveles de encabezado
como necesite. Observe cómo podemos especificar una concatenación de cadenas y
variables como un argumento único para la función sub ().
$ do.outline ch02
Capítulo 2 Comprensión de las operaciones básicas
2.1 Awk, de Sed y Grep, de Ed
2.2 Sintaxis de línea de comandos
2.2.1 Scripting
2.2.2 Lista de correo de muestra
2.3 Usando Sed
2.3.1 Especificación de instrucciones simples
2.3.2 Archivos de script
2.4 Usando Awk
2.5 Uso de Sed y Awk juntos
Caso de conversión
POSIX awk proporciona dos funciones para convertir el caso de caracteres dentro de una
cadena. Las funciones son tolower () y toupper (). Cada uno toma un solo argumento de
cadena y devuelve una copia de esa cadena, con todos los caracteres de un caso
convertidos al otro (de arriba a abajo y de abajo a arriba, respectivamente). Su uso es
sencillo:
1, 2, 3, y ¡vamos!
$ awk '{printf ("<% s>, <% s> \ n", tolower ($ 0), toupper ($ 0))}' prueba <¡hola, mundo!>, <¡HOLA,
MUNDO!>
<¡adiós mundo cruel!>, <¡Adiós mundo cruel!>
<1, 2, 3, ¡y vamos!>, <1, 2, 3, ¡Y LEJOS!>
La función match ()
La función match () le permite determinar si una expresión regular coincide con una
cadena especificada. Se necesitan dos argumentos, la cadena y la expresión regular. (Esta
función es confusa porque la expresión regular está en la segunda posición, mientras que
está en la primera posición para las funciones de sustitución).
El valor devuelto por esta función es 5, la posición del carácter de "U", la primera letra
mayúscula en la cadena.
La función match () también establece dos variables del sistema: RSTART y RLENGTH.
RSTART contiene el mismo valor devuelto por la función, la posición inicial de la
subcadena. RLENGTH contiene la longitud de la cadena en caracteres (no la posición
final de la subcadena). Cuando el patrón no coincide, RSTART se establece en 0 y
RLENGTH se establece en -1. En el ejemplo anterior, RSTART es igual a 5 y
RLENGTH es igual a 4. (Agregarlos juntos le da la posición del primer personaje
después del partido).
Veamos un ejemplo bastante simple que imprime una cadena que coincide con una
expresión regular especificada, que demuestra la "extensión de la coincidencia", como se
discutió en el Capítulo 3, Comprensión de la sintaxis de expresión regular. El siguiente
script de shell toma dos argumentos de línea de comandos: la expresión regular, que debe
especificarse entre comillas, y el nombre del archivo a buscar.
El primer parámetro de la línea de comandos se pasa como el valor del patrón n. Tenga
en cuenta que $ 1 está rodeado de comillas, necesarias para proteger cualquier espacio
que pueda aparecer en la expresión regular. La función match () aparece en una expresión
condicional que controla la ejecución del único procedimiento en este script awk. La
función match () devuelve ns 0 si no se encuentra el patrón, y un valor distinto de cero
(RSTART) si se encuentra, lo que permite que el valor devuelto se use como condición.
Si el registro actual coincide
216 Capítulo 9: Funciones
Su e es una prueba, dada una expresión regular que coincide con "emp" y cualquier
número de caracteres hasta un espacio en blanco:
$ coincide con "emp [ˆ] *" staff.txt empleados
empleado
empleado.
empleo,
empleador
empleo
empleado del
empleado
El script de coincidencia podría ser una herramienta útil para mejorar su comprensión de
las expresiones regulares.
El siguiente script usa la función match () para localizar cualquier secuencia de letras
mayúsculas para que puedan convertirse en minúsculas. Compárelo con el programa de
mayúsculas que se muestra anteriormente en el capítulo.
En este script, la función match () aparece en una expresión condicional que determina si
se ejecutará un ciclo while. Al colocar esta función en un bucle, aplicamos el cuerpo del
bucle tantas veces como se produce el patrón en el registro de entrada actual.
Funciones de cuerda 217
$ prueba de gato
$ prueba inferior
De vez en cuando, una palabra que escribo aparece en mayúsculas.
Tenga en cuenta que puede cambiar la expresión regular para evitar la coincidencia de
letras mayúsculas individuales haciendo coincidir una secuencia de dos o más caracteres
en mayúscula, utilizando: "/ [AZ] [AZ] + /". Esto también requeriría revisar la forma en
que se realizó la conversión en minúsculas usando gsub (), ya que coincide con un solo
carácter en la línea.
Por ejemplo, si hace coincidir una cadena con la función match (), puede seleccionar
caracteres o una subcadena en la cabecera o cola de la cadena. Dados los valores de
RSTART y RLENGTH, puede usar la función substr () para extraer los caracteres. En el
siguiente ejemplo, reemplazamos el segundo de dos puntos con un punto y coma. No
podemos usar gsub () para hacer el reemplazo porque “/: /” coincide con el primer colon
y “/: [ˆ:] *: /” coincide con toda la cadena de caracteres. Podemos usar match () para
hacer coincidir la cadena de caracteres y extraer el último carácter de la cadena.
# reemplace el segundo colon con punto y coma usando match, substr if (match ($ 1, /: [ˆ:] *: /)) {
before = substr ($ 1, 1, (RSTART + RLENGTH - 2)) after =
substr ($ 1, (RSTART + RLENGTH))
$ 1 = antes de ";" después
}
* Tal vez se pregunte, "¿por qué no usar tolower ()?" Buena pregunta. Algunas versiones anteriores de nawk,
incluida la de los sistemas SunOS 4.1.x, no tienen tolower () y toupper (); Por lo tanto, es útil saber cómo hacerlo
usted mismo.
218 Capítulo 9: Funciones
La función match () se coloca dentro de una declaración condicional que prueba que se
encontró una coincidencia. Si hay una coincidencia, usamos la función substr () para
extraer la subcadena antes del segundo colon, así como la subcadena después. Luego
concatenamos antes, el literal ";", y después, asignándolo a $ 1.
Se puede colocar una definición de función en cualquier parte de un script donde pueda
aparecer una regla de acción de patrón. Por lo general, colocamos las definiciones de
funciones en la parte superior del script antes de las reglas de acción de patrón. Una
función se define utilizando la siguiente sintaxis:
función nombre (lista de parámetros) {
declaraciones
}
Las nuevas líneas después de la llave izquierda y antes de la llave derecha son opcionales.
También puede tener una nueva línea después del paréntesis de cierre de la lista de
parámetros y antes de la llave izquierda.
La lista de parámetros es una lista de variables separadas por comas que se pasan como
argumentos a la función cuando se llama. El cuerpo de la función consta de una o más
declaraciones. La función generalmente contiene una declaración de devolución que
devuelve el control hasta ese punto en el script donde se llamó a la función; a menudo
tiene una expresión que también devuelve un valor.
regreso expresión
Esta función toma tres argumentos, insertando una cadena INS en otra cadena STRING
**
después del carácter en la posición POS. El cuerpo de esta función usa la función substr
() para dividir el valor de STRING en dos partes. La declaración de devolución devuelve
una cadena que es el resultado de concatenar la primera parte de STRING, la cadena INS
y la última parte de STRING. Una llamada de función puede aparecer en cualquier lugar
donde pueda aparecer una expresión. Por lo tanto, la siguiente declaración:
inserto de impresión ($ 1, 4, "XX")
Sin embargo, las variables definidas en el cuerpo de la función son variables globales, por
defecto. Dada la definición anterior de la función inser t (), las variables temporales
before_tmp y after_tmp son visibles fuera de la función. Awk proporciona lo que sus
desarrolladores llaman un medio "poco elegante" para declarar variables locales a una
función, y eso es especificando esas variables en la lista de parámetros.
* Hemos utilizado una convención de dar todos los nombres en mayúsculas a nuestros parámetros. Esto es
principalmente para hacer que la explicación sea más fácil de seguir. En la práctica, probablemente no sea una buena
idea, ya que resulta mucho más fácil tener un conflicto de parámetros accidentalmente con una variable del sistema.
220 Capítulo 9: Funciones
# rutina principal
{
print "La función devuelve", inserta ($ 1, 4, "XX") print
"El valor de $ 1 después es:", $ 1
print "El valor de STRING es:", STRING print "El valor
de before_tmp:", before_tmp print "El valor de
after_tmp:", after_tmp
}
Como muestra este ejemplo, $ 1 se pasa "por valor" a la función. Esto significa que se
hace una copia del valor cuando se llama a la función y la función manipula la copia, no
el original. Las matrices, sin embargo, se pasan "por referencia". Es decir, la función no
funciona con una copia de la matriz, sino que se pasa a la matriz misma. Por lo tanto,
cualquier cambio que la función realice en la matriz es visible fuera de la función. (Esta
distinción entre variables "escalares" y matrices también es válida para las funciones
escritas en el lenguaje C). La siguiente sección presenta un ejemplo de una función que
opera en una matriz.
* La documentación lo llama una falla sintáctica.
Escribe tus propias funciones 221
Definimos una función que toma dos argumentos, el nombre de la matriz y el número de
elementos en la matriz. Esta función se puede llamar de esta manera:
sort (sortedpick, NUM)
La definición de la función enumera los dos argumentos y las tres variables locales
utilizadas en la función.
# ordenar los números en orden ascendente
clasificación de funciones (ARRAY, ELEMENTS, temp, i,
j) {para (i = 2; i <= ELEMENTOS; ++ i) {
para (j = i; (j-1) en ARRAY && ARRAY [j-1]> ARRAY [j]; --j) {temp =
ARRAY [j]
ARRAY [j] = ARRAY [j-1]
ARRAY [j-1] = temp
}
}
regreso
}
Su mensaje es positivo:
$ lotto 7 35 Escoge 7 de 35
671719242935
De hecho, muchos de los scripts que desarrollamos en este capítulo podrían convertirse
en funciones. Por ejemplo, si solo tuviéramos la versión original de 1987 de nawk,
podríamos querer escribir nuestras propias funciones tolower () y toupper ().
* Tenemos que probar ese j-1 en ARRAY, primero, para asegurarnos de que no se caiga del extremo frontal de la
matriz.
† El regreso es opcional aquí; "Caerse al final" de la función tendría el mismo efecto. Como las funciones pueden
tener valores de devolución, es una buena idea usar siempre una declaración de devolución.
222 Capítulo 9: Funciones
# rutina principal
{
# recorrer los campos 2 a NF y asignar valores a
# conjunto de grados con nombre
para (i = 2; i <= NF; ++ i)
grados [i-1] = $ i
# bucle de salida
para (j = 1; j <= NF-1; ++ j)
printf ("% d", grados [j])
printf ("\ n")
}
Como otro ejercicio, podría escribir una versión de la función de clasificación que tome
un tercer argumento que indique una clasificación ascendente o descendente.
Este comando supone que grade.awk está en el directorio de trabajo y que la función de
clasificación se define en sort.awk en el directorio / usr / local / shar e / awk.
Recuerde documentar las funciones claramente para que entienda cómo funcionan
cuando desee reutilizarlas.
La última sección de cada página de manual de Xlib se llama "Comandos relacionados" (ese
es el argumento de un .SH) y es seguida por una lista de comandos (a menudo 10 o 20) que
ahora están en orden aleatorio. Seria mas
útiles y profesionales si estuvieran alfabetizados. Actualmente, los comandos están separados
por una coma después de cada uno, excepto el último, que tiene un punto.
La pregunta es: ¿podría awk alfabetizar estas listas? Estamos hablando de un par de
cientos de páginas de manual. Nuevamente, no se preocupe si este es un trabajo más
grande de lo que parece para alguien que no sabe lo que está involucrado.
Lenny
* La versión SunOS 4.1.x de nawk no admite múltiples archivos de script. Esta característica tampoco estaba en la
versión original de 1987 de nawk. Fue agregado en 1989 y ahora es parte de POSIX awk.
224 Capítulo 9: Funciones
Para ver de qué está hablando, a continuación se muestra una versión simplificada de una
página de manual de Xlib:
.SH "Nombre"
XSubImage: crea una subimagen a partir de parte de una imagen.
.
.
.
.SH "Comandos relacionados"
XDestroyImage, XPutImage, XGetImage,
XCreateImage, XGetSubImage, XAddPixel,
XPutPixel, XGetPixel, ImageByteOrder.
Puede ver que los nombres de los comandos relacionados aparecen en varias líneas
siguiendo el encabezado. También puede ver que no están en un orden particular.
Una vez que el encabezado "Comandos relacionados" coincide, imprimimos esa línea y
luego establecemos un indicador, la variable relcmds, que indica que se deben recopilar
**
las líneas de entrada posteriores. El segundo procedimiento en realidad recopila cada
línea en la lista de comandos variable. El tercer procedimiento se ejecuta para todas las
demás líneas, simplemente imprimiéndolas.
Cuando se han leído todas las líneas de entrada, se ejecuta el procedimiento END y
sabemos que nuestra lista de comandos está completa. Antes de dividir los comandos en
campos, eliminamos cualquier número de espacios después de una coma. A continuación,
eliminamos el período final y los espacios finales. Finalmente, creamos la matriz comAr
ray usando la función split (). Pasamos esta matriz como argumento a la función sor t (),
y luego imprimimos los valores ordenados.
Una vez más, la virtud de llamar a una función para hacer la clasificación en lugar de
escribir o copiar el código para hacer la misma tarea es que la función es un módulo que
ha sido probado
* La función getline presentada en el próximo capítulo proporciona una forma más sencilla de controlar la lectura
de líneas de entrada.
226 Capítulo 9: Funciones
por supuesto y tiene una interfaz estándar. Es decir, sabes que funciona y sabes cómo
funciona. Cuando encuentre el mismo código de clasificación en la versión awk, que
utiliza diferentes nombres de variables, debe escanearlo para verificar que funciona de la
misma manera que otras versiones. Incluso si copiara las líneas en otro programa, tendría
que hacer cambios para acomodar las nuevas circunstancias. Con una función, todo lo
que necesita saber es qué tipo de argumentos espera y su secuencia de llamada. El uso de
una función reduce la posibilidad de error al reducir la complejidad del problema que está
resolviendo.
Debido a que este script presupone que la función sor t () existe en un archivo separado,
debe invocarse utilizando las múltiples opciones -f:
$ awk -f sort.awk -f sorter.awk prueba