Está en la página 1de 37

9

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

Función Awk Descripción


cos (x) Devuelve el coseno ns de x (x está en radianes).
exp (x) Vuelve e a la potencia x.
int (x) Devuelve ns valor truncado de x.
log (x) Devuelve el logaritmo natural (base-e) de x.
sin (x) Devuelve ns seno de x (x está en radianes).
sqr t (x) Devuelve n cuadrado y raíz de x.
atan2 (y, x) Devuelve ns arctangent de y / x en el rango -π a π.
rand () Devuelve ns número pseudoaleatorio r, donde e 0 <= r <1.
srand (x) Establece nueva semilla para rand (). Si no hay semilla
especificado, utiliza la hora del día. Devuelve la semilla vieja.

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 π.

La función exp () usa la exponencial natural, que también se conoce como


exponenciación base-e. La expresion
exp (1)

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.

La función log () da la inversa de la función exp (), el logaritmo natural de x. La función


sqr t () toma un solo argumento y devuelve la raíz cuadrada (positiva) de ese argumento.

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)

El resultado de estas declaraciones se muestra a continuación:


33,3333
33

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).

Generación de números aleatorios


La función rand () genera un número de punto flotante pseudoaleatorio entre 0 y 1. La
función srand () establece la semilla o el punto de partida para la generación de números
aleatorios. Si se llama a srand () sin argumento, usa la hora del día para generar la
semilla. Con un argumento x, srand () usa x como semilla.

* 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 ()
}

Imprimimos el resultado de la función rand () dos veces, y luego llamamos a la función


srand () antes de imprimir el resultado de la función rand () dos veces más. Ejecutemos el
script.

$ 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 ()

# obtener un número aleatorio


select = 1 + int (rand () * TOPNUM)
# imprimir selección
imprimir seleccionar
}'

El script de shell espera un único argumento de la línea de comando y este se pasa al


programa como "TOPNUM = $ 1", utilizando la opción -v. Toda la acción sucede en el
procedimiento COMIENZO. Como no hay otras declaraciones en el programa, awk se
cierra cuando finaliza el procedimiento BEGIN.

La rutina principal primero llama a la función srand () para sembrar el generador de


números aleatorios. Luego obtenemos un número aleatorio llamando a la función rand ():
select = 1 + int (rand () * TOPNUM)

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

Debido a que la función rand () devuelve un número entre 0 y 1, lo multiplicamos por


TOPNUM para obtener un número entre 0 y TOPNUM. Luego truncamos el número para
eliminar los valores fraccionarios y luego sumamos 1 al número. Este último es
Funciones aritméticas 207

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.

Ella es el guión de lotería:


awk -v NUM = $ 1 -v TOPNUM = $ 2 '
# lotería: elige x números aleatorios de y
# rutina principal
EMPEZAR {
# prueba de línea de comando args; NUM = $ 1, cuántos números elegir
## TOPNUM = $ 2, último número de serie si (NUM <= 0)

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 ()

# bucle hasta que tengamos NUM selecciones


para (j = 1; j <= NUM; ++ j) {
# bucle para encontrar una selección aún no vista hacer {

select = 1 + int (rand () * TOPNUM)}


while (seleccionar en selección)
recoger [seleccionar] = seleccionar
}
# recorrer la matriz e imprimir selecciones. para (j en selección)
printf ("% s", seleccione [j])
printf ("\ n")
}'

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.

Finalmente, el programa recorre la matriz de selección e imprime los elementos. Esta


versión del script de lotería deja una cosa fuera. Vea si puede decir qué es si lo
ejecutamos nuevamente:

$ 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:

# crear una matriz indexada numéricamente para ordenar i = 1

for (j in pick) sortedpick [i ++] = pick [j]

El programa de lotería está configurado para hacer todo en el bloque BEGIN. No se


procesa ninguna entrada. Sin embargo, puede revisar este script para leer una lista de
nombres de un archivo y para cada nombre generar una "selección rápida".

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

Tabla 9−2: Funciones de cadena incorporadas de Awk

Función Awk Descripción

gsub (r, s, t) Sustituye globalmente s por cada coincidencia de la expresión regular r en


la cuerda t. Devuelve el número de sustituciones. Si t no se suministra,
el valor predeterminado es $ 0.
índice (s, t) Devuelve la posición de la subcadena t en la cadena so cero si no está presente.
Devuelve ns longitud de cadena s o longitud de $ 0 si no se proporciona
longitud (s) cadena.
partido (s, r) Devuelve la posición en s donde la expresión regular r
comienza, o 0 si no se encuentran ocurrencias. Establece los valores de
RSTART
y longitud.
Analiza la cadena s en elementos de la matriz a usando el separador de campo
división (s, a, sep) sep;
devuelve ns número de elementos. Si no se suministra sep, se usa FS.
Formación
la división funciona de la misma manera que la división de campo.
spr intf ("fmt", expr) Utiliza pr intf para la especificación de mat para expr.
sub (r, s, t) Sustituye s por la primera coincidencia de la expresión regular r en la cadena t.
Devuelve ns 1 si tiene éxito; 0 de lo contrario. Si t no se suministra, el valor
predeterminado es
$ 0.
substr (s, p, n) Devuelve la subcadena ns de la cadena s en la posición inicial p hasta
longitud máxima de n. Si no se proporciona n, el resto de la cadena de
pags es usado
tolower (s) Traduce todos los caracteres en mayúscula de la cadena s a minúsculas y
devuelve la nueva cadena.
toupper (s) Traduce todos los caracteres en minúscula de la cadena s a mayúsculas y
devuelve la nueva cadena.

La función split () se introdujo en el capítulo anterior en la discusión sobre matrices.

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)
...
}

Un bucle proporciona números del 97 al 122, que producen caracteres ASCII de la a la z.


210 Capítulo 9: Funciones

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")

El valor de pos es 2. Si no se encuentra la subcadena, la función index () devuelve ns 0.

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)

También puede proporcionar un tercer argumento que es el número de caracteres para


devolver n.
El siguiente ejemplo devuelve solo el código de área:
area_code = substr ("707-555-1111", 1, 3)

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.

awk '# mayúsculas: escribe en mayúscula la primera letra de


la primera palabra # inicializa cadenas
COMENZAR {upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lower = "abcdefghijklmnopqrstuvwxyz"
}

# para cada línea de entrada


{
# obtener el primer carácter de la primera palabra FIRSTCHAR = substr ($ 1, 1, 1)
# obtener la posición de FIRSTCHAR en minúscula; si 0, ignore si (CHAR = index (lower, FIRSTCHAR))
# cambiar $ 1, usando la posición para recuperar
# carácter en mayúscula
$ 1 = substr (superior, CHAR, 1) substr ($ 1, 2)
# imprimir registro imprimir $ 0
}'

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.

$ usuario root de mayúsculas Usuario raíz dale Dale

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.

El Capítulo 13, Una mezcla de secuencias de comandos, contiene una secuencia de


comandos que utiliza la función length () para dividir líneas de más de 80 columnas de
ancho.
212 Capítulo 9: Funciones

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).

Las funciones de sustitución cambian la cadena especificada directamente. Puede esperar,


dada la forma en que funcionan las funciones, que la función devuelve la nueva cadena
creada cuando se realiza la sustitución. Las funciones de sustitución en realidad
devuelven el número de sustituciones realizadas. sub () siempre devolverá n 1 si tiene
éxito; ambos retornan n 0 si no tienen éxito. Por lo tanto, puede probar el resultado para
ver si se realizó una sustitución.

Por ejemplo, el siguiente ejemplo usa gsub () para reemplazar todas las apariciones de
"UNIX" con "POSIX".
if (gsub (/ UNIX /, "POSIX"))
impresión

La instrucción condicional prueba el valor devuelto de gsub () de modo que la línea de


entrada actual se imprima solo si se realiza un cambio.

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")

Si la entrada es "el sistema operativo UNIX", la salida es "el sistema operativo \


fBUNIX \ fR".

En el Capítulo 4, Escritura de scripts sed, presentamos el siguiente script sed llamado


do.outline:

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:

awk '# do.outline - encabezados de números en el capítulo.


{
gsub (/ "/," ")
}
/ˆ\.Se/ {
sub (/ˆ\.Se /, "Capítulo")
ch = $ 2
ah = 0
bh = 0
impresión
siguiente
}
/ˆ\.Ah/ {
sub (/ˆ\.Ah /, "\ t" ch "." ++ ah "")
bh = 0
impresión
siguiente
}
/ˆ\.Bh/ {
sub (/ˆ\.Bh /, "\ t \ t" ch "." ah "." ++ bh "")
impresión
PS

En esta versión, dividimos cada encabezado en su propia regla de coincidencia de


patrones. Esto no es necesario, pero parece más eficiente, ya que sabemos que una vez
que se aplica una regla, no necesitamos mirar a los demás. Tenga en cuenta el uso de la
siguiente declaración para evitar un examen más detenido de una línea que ya ha sido
identificada.
214 Capítulo 9: Funciones

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

Si desea la opción de elegir números o letras, puede mantener ambos programas y


construir un envoltorio de shell que use algún indicador para determinar qué programa
debe invocarse.

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:

$ prueba de gato ¡Hola Mundo! ¡Adiós mundo cruel!

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!>

Tenga en cuenta que los caracteres no alfabéticos no se modifican.


Funciones de cuerda 215

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).

La función match () devuelve la posición inicial de la subcadena que coincide con la


expresión regular. Puede considerarlo una relación estrecha con la función index (). En el
siguiente ejemplo, la expresión regular coincide con cualquier secuencia de letras
mayúsculas en la cadena "el sistema operativo UNIX".
partido ("el sistema operativo UNIX", / [AZ] + /)

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.

awk '# match: imprime la cadena que coincide con la línea


# para líneas coinciden con el patrón ($ 0, patrón) {
# extraer el patrón de coincidencia de cadenas usando
# posición inicial y longitud de la cuerda en $ 0
# cadena de impresión
imprimir substr ($ 0, RSTART, RLENGTH)
} 'patrón = "$ 1" $ 2

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

el patrón, luego la cadena se extrae de $ 0, utilizando los valores de RSTART y


RLENGTH en la función substr () para especificar la posición inicial de la subcadena que
se extraerá y su longitud. La subcadena está impresa. Este procedimiento solo coincide
con la primera aparición en $ 0.

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.

awk '# lower - cambia mayúscula a minúscula # inicializa


cadenas
COMENZAR {upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lower = "abcdefghijklmnopqrstuvwxyz"
}

# para cada línea de entrada


{
# ver si hay una coincidencia para todos los límites mientras que (coincidencia ($ 0, / [AZ] + /))
# obtener cada letra mayúscula
para (x = RSTART; x <RSTART + RLENGTH; ++ x) {
CAP = substr ($ 0, x, 1)
CHAR = índice (superior, CAP)
# sustituya minúsculas por gsub superior (CAP, substr (inferior, CHAR,
1))
}

# imprimir registro imprimir $ 0


PS

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

La expresión regular coincide con cualquier secuencia de letras mayúsculas en $ 0. Si se


hace una coincidencia, un bucle for realiza la búsqueda de cada carácter en la subcadena
que coincidió, similar a lo que hicimos en el programa de ejemplo de mayúsculas, que se
muestra anteriormente en este capítulo. Lo que es diferente es cómo usamos las variables
del sistema RSTART y RLENGTH. RSTART inicializa la variable de contador x. Se
utiliza en la función substr () para extraer un carácter a la vez desde $ 0, comenzando con
el primer carácter que coincida con el patrón. Al agregar RLENGTH a RSTART,
obtenemos la posición del primer personaje después de los que coinciden con el patrón.
Es por eso que el bucle usa "<" en lugar de "<=". Al final, usamos gsub () para
**
reemplazar la letra mayúscula con la letra minúscula correspondiente. Tenga en cuenta
que usamos gsub () en lugar de sub () porque nos ofrece la ventaja de hacer varias
sustituciones si hay varias instancias de la misma letra en la línea.

$ 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.

En nuestra discusión sobre el comando de sustitución de sed, viste cómo guardar y


recuperar una parte de una cadena que coincide con un patrón, usando \ (y \) para rodear
el patrón n que se guardará y \ n para recuperar la cadena guardada en el patrón de
reemplazo. Desafortunadamente, las funciones de sustitución estándar de awk no ofrecen
una sintaxis equivalente. Sin embargo, la función match () puede resolver muchos de
estos problemas.

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.

Puede ver ejemplos de la función match () en uso en el Capítulo 12, Aplicaciones


completas.

Escribe tus propias funciones


Con funciones definidas por el usuario, awk permite al programador novato dar un paso
* *
más hacia la programación en C escribiendo programas que hacen uso de funciones
autónomas. Cuando escribe una función correctamente, ha definido un componente de
programa que puede reutilizarse en otros programas. El beneficio real de la modularidad
se hace evidente a medida que los programas crecen en tamaño o en edad, y a medida que
aumenta el número de programas que escribe.

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

El siguiente ejemplo muestra la definición de una función inser t ():


función insertar (STRING, POS, INS) {
before_tmp = substr (STRING, 1, POS)
after_tmp = substr (STRING, POS + 1)
return before_tmp INS after_tmp
}
* O programar en cualquier otro lenguaje tradicional de alto nivel.
Escribe tus propias funciones 219

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")

Si el valor de $ 1 es "Hola", entonces esto devuelve "HellXXo". Tenga en cuenta que al


llamar a una función definida por el usuario, no puede haber espacios entre el nombre de
la función y el paréntesis izquierdo. Esto no es cierto para las funciones integradas.

Es importante comprender la noción de variables locales y globales. Una variable local es


una variable que es local a una función y no se puede acceder fuera de ella. Una variable
global, por otro lado, se puede acceder o cambiar en cualquier parte del script. Puede
haber efectos secundarios potencialmente dañinos de las variables globales si una función
cambia una variable que se usa en otra parte del script. Por lo tanto, por lo general, es una
buena idea eliminar las variables globales en una función.

Cuando llamamos a la función inser t (), y especificamos $ 1 como primer argumento,


luego se pasa una copia de esa variable a la función, donde se manipula como una
variable local llamada STRING. Todas las variables en la lista de parámetros de la
definición de función son variables locales y sus valores no son accesibles fuera de la
función. Del mismo modo, los argumentos en la llamada a la función no son cambiados
por la función misma. Cuando la función inser t () retorna, el valor de $ 1 no cambia.

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.

Las variables temporales locales se colocan al final de la lista de parámetros. Esto es


esencial; Los parámetros en la lista de parámetros reciben sus valores, en orden, de los
valores pasados en la llamada a la función. Cualquier parámetro adicional, como las
variables normales de awk, se inicializa en la cadena vacía. Por convención, las variables
locales están separadas de los parámetros "reales" por varios espacios. Por ejemplo, el
siguiente ejemplo muestra cómo definir la función inser t () con dos variables locales.

* 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

función de inserción (STRING, POS, INS, before_tmp, after_tmp) {


cuerpo
}
**
Si esto parece confuso, ver cómo funciona el siguiente script podría ayudar:

función de inserción (STRING, POS, INS, before_tmp)


{before_tmp = substr (STRING, 1, POS) after_tmp =
substr (STRING, POS + 1) return before_tmp INS
after_tmp

# 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
}

Observe que especificamos before_tmp en la lista de parámetros. En la rutina principal,


llamamos a la función inser t () e imprimimos su resultado. Luego imprimimos diferentes
variables para ver cuál es su valor, si lo hay. Ahora ejecutemos el script anterior y
observemos la salida:

$ echo "Hola" | awk -f insert.awk -La función devuelve HellXXo


El valor de $ 1 después es: Hola. El
valor de STRING es:
El valor de before_tmp: El valor
de after_tmp: o

La función inser t () devuelve "HellXXo", como se esperaba. El valor de $ 1 es el mismo


después de que se llamó a la función como era antes. La variable STRING es local para la
función y no tiene un valor cuando se llama desde la rutina principal. Lo mismo es cierto
para before_tmp porque su nombre se colocó en la lista de parámetros para la definición
de la función. La variable after_tmp que no se especificó en la lista de parámetros tiene
un valor, la letra "o".

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

Escribir una función sor t


Anteriormente en este capítulo presentamos el script de lotería para elegir x números
aleatorios de una serie de números y. Ese script no clasificó la lista de números que
fueron seleccionados. En esta sección, desarrollamos una función sor t para elementos de
una matriz.

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
}

El cuerpo de la función implementa una ordenación por inserción. Este algoritmo de


clasificación es muy simple. Recorremos cada elemento de la matriz y lo comparamos
con el valor que lo precede. Si el primer elemento es mayor que el segundo, se
intercambian los elementos primero y segundo. * *Para intercambiar los valores, usamos
una variable temporal para guardar una copia del valor mientras sobrescribimos el
original. El ciclo continúa intercambiando elementos adyacentes hasta que todos estén en
orden. Al final de la función, utilizamos la declaración de devolución para simplemente

devolver el control. La función no necesita devolver la matriz a la rutina principal
porque la matriz en sí misma ha cambiado y se puede acceder a ella directamente.

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

El valor de escribir la función sor t () de manera general es que puede reutilizarla


fácilmente. Para demostrar esto, tomaremos la función de clasificación anterior y la
usaremos para clasificar las calificaciones de los estudiantes. En el siguiente script,
leemos todas las calificaciones de los alumnos en una matriz y luego llamamos a sor t ()
para poner las calificaciones en orden ascendente.
# grade.sort.awk - script para ordenar las calificaciones de los estudiantes
# entrada: nombre del alumno seguido de una serie de calificaciones

# función de clasificación: ordena los números en orden ascendente


clasificación de funciones (ARRAY, ELEMENTS, temp, i, j)
{para (i = 2; i <= ELEMENTOS; ++ i)

para (j = i; ARRAY [j-1]> ARRAY [j]; --j) {


temp = ARRAY [j]
ARRAY [j] = ARRAY [j-1]
ARRAY [j-1] = temp
}
regreso
}

# 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

# llamar a la función de clasificación para ordenar elementos (grados, NF-1)

# escriba el nombre del estudiante


printf ("% s:", $ 1)

# bucle de salida
para (j = 1; j <= NF-1; ++ j)
printf ("% d", grados [j])
printf ("\ n")
}

Tenga en cuenta que la rutina de clasificación es idéntica a la versión anterior. En este


ejemplo, una vez que hemos ordenado las calificaciones, simplemente las enviamos:
$ awk -f grade.sort.awk grados.test Mona: 70 70 77 83 85 89
juan: 78 85 88 91 92 94
andrea: 85 89 90 90 94 95
jaspe: 80 82 84 84 88 92
burro: 60 60 61 62 64 80
ellis: 89 90 92 96 96 98

Sin embargo, podría, por ejemplo, eliminar el primer elemento de la matriz de


clasificación si desea promediar las calificaciones de los estudiantes después de eliminar
la calificación más baja.
Escribe tus propias funciones 223

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.

Mantener una biblioteca de funciones


Es posible que desee colocar una función útil en su propio archivo y almacenarla en un
directorio central. Awk permite múltiples usos de la opción -f para especificar más de un
* *
archivo de programa. Por ejemplo, podríamos haber escrito el ejemplo anterior de
modo que la función de clasificación se coloque en un archivo separado del programa
principal grade.awk. El siguiente comando especifica ambos archivos de programa:
$ awk -f grade.awk -f /usr/local/share/awk/sort.awk grados.test

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.

NOTA No puede poner una secuencia de comandos en la línea de comando y


también usar la opción -f para especificar un nombre de archivo para una
secuencia de comandos.

Recuerde documentar las funciones claramente para que entienda cómo funcionan
cuando desee reutilizarlas.

Otro ejemplo ordenado


Lenny, nuestro editor de producción, regresa con otra solicitud.
Valle:

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.

Lo mejor para usted y los suyos,

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.

Ordenar la lista de comandos relacionados es en realidad bastante simple, dado que ya


hemos cubierto la clasificación. La estructura del programa es algo interesante, ya que
debemos leer varias líneas después de hacer coincidir el encabezado "Comandos
relacionados".

Al observar la entrada, es obvio que la lista de comandos relacionados es la última


sección del archivo. Todas las demás líneas, excepto estas, queremos imprimirlas tal cual.
La clave es hacer coincidir todas las líneas desde el encabezado "Comandos
relacionados" hasta el final del archivo. Nuestro script puede constar de cuatro reglas, que
coinciden:
1. El encabezado "Comandos relacionados"
2. Las líneas que siguen ese encabezado
3. Todas las otras líneas
4. Después de haber leído todas las líneas (FIN)

La mayor parte de la "acción" tiene lugar en el procedimiento FIN. Ahí es donde


ordenamos y sacamos la lista de comandos. Aquí está el guión:
# sorter.awk - ordena la lista de comandos relacionados
# requiere sort.awk como función en un archivo separado BEGIN {relcmds = 0}

# 1 Comandos relacionados con coincidencias; habilitar bandera x


/\.SH "Comandos relacionados" / {
impresión
relcmds = 1
siguiente
}

# 2 Aplicar a las líneas que siguen a "Comandos relacionados"


(relcmds == 1) {
commandList = commandList $ 0
}
Escribe tus propias funciones 225

# 3 Imprima todas las demás líneas, tal cual.


(relcmds == 0) {imprimir}

# 4 ahora ordena y muestra la lista de comandos


FIN {
# eliminar espacios iniciales y período final. gsub (/, * /, ",", commandList) gsub (/ \. * $ /, "",
commandList)
# lista dividida en matriz
sizeOfArray = split (commandList, comArray, ",")
# sort
sort (comArray, sizeOfArray)
# elementos de salida
para (i = 1; i <sizeOfArray; i ++)
printf ("% s, \ n", comArray [i])
printf ("% s. \ n", comArray [i])
}

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.

Este programa genera el siguiente resultado:


$ awk -f sorter.awk test
.SH "Nombre"
XSubImage: crea una subimagen a partir de parte de una imagen.
.SH "Comandos
relacionados"
ImageByteOrder,
XAddPixel, XCreateImage,
XDestroyImage,
XGetImage, XGetPixel,
XGetSubImage, XPutImage,
XPutPixel.

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

donde la función sor t () se define en el archivo sort.awk.

También podría gustarte