Esta página puede ser redistribuida libremente bajo los términos de la licencia GPL. Vease ( GPL texto original ) o si lo prefiere (Traducción española no oficial de la GPL) Al margen de las obligaciones legales que se derivan del uso de esta licencia rogamos sea respetada la referencia a su lugar de publicación original www.ciberdroide.com. y a su autor original Antonio Castro Snurmacher (Madrid 01/01/2000).

Ausencia de Garantía

Esta ausencia de garantía se hace extensa a cualquier tipo de uso de este material y muy especialmente a las prácticas, ejercicios, y de ejemplos que encuentre en estas páginas. Deberá trabajar siempre salvo indicación contraria con un SO Linux y con un usario distinto de 'root' sin privilegios especiales. Como directorio de trabajo se procurará usar el directorio '/tmp' o algún otro que no contenga información valiosa. Tampoco se considera buena idea practicar en una máquina que contenga información valiosa.

Todo esto son recomendaciones de prudencia. En cualquier caso si algo sale mal toda la responsabilidad será únicamente suya. En ningún caso podrá reclamar a nadie por daños y perjuicios derivados del uso de este material. Para más información lea el contenido de la licencia GPL y abstengase de hacer prácticas si no está dispuesto a asumir toda la responsabilidad.

Nociones de programación en awk

Que es awk y para que se usa
La palabra 'awk' se usa tanto para referirse a un lenguaje de manipulación de ficheros de datos como para referirse a su interprete.

Dado que los SO tipo Unix incluido Linux acostumbran con mucha frecuencia a usar ficheros de configuración del sistema en formatos de de texto perfectamente legibles y editables se diseño un lenguaje para poder procesar este tipo de ficheros de datos en formato de texto.

Cuando un programa necesita una velocidad muy alta para acceder a unos datos o para modificarlos se utilizan estructuras de datos más sofisticadas.

En muchos otros casos un fichero de configuración será accedido de forma muy ocasional, y resulta más interesante usar un formato de texto sencillo. Por ejemplo hay ficheros de configuración que solo se usan durante la carga de un programa. Algunos de estos programas suelen cargarse una sola vez mientras arranca el sistema y luego en condiciones normales permanecen arrancados todo el tiempo.

'awk' nació en 1978 como un lenguaje pequeño y sencillo pero desde entonces ha evolucionado mucho y en la actualidad se puede afirmar que es un lenguaje muy potente y versátil. Imposible tratarlo en profundidad en un curso como este.

'awk' es un complemento muy bueno para su uso con shell-script. Esta lección no va a condicionar la asimilación de lecciones posteriores pero recomendamos que como mínimo le de un breve repaso ya que 'awk' puede resultar extremadamente útil en determinadas circunstancias.

Nos vamos a conformar con explicar unas pocas cosas porque con ello conseguiremos dos objetivos. El primero que pueda usarlo para un limitado tipo de tareas bastante frecuentes, y el segundo que conozca su existencia y para que se usa. De esta forma puede ampliar conocimientos por su cuenta cuando lo necesite.

Nos vamos a centrar en el procesamiento de datos en los cuales cada línea estará estructurada en campos. Estos campos estarán delimitados entre si por algún carácter o por alguna secuencia especial de caracteres especialmente reservado para ello. Esta secuencia será el delimitador de campos y no debe aparecer en el interior de ningún campo. Cada línea equivale a un registro.

La mayoría de las bases de datos, y hojas de cálculo permiten volcar los datos en formato de texto para poder ser exportados entre distintas bases de datos. Estas salidas se pueden procesar fácilmente mediante 'awk'. También se puede usar 'awk' con la salida de diversos programas. Esto permite entre otras cosas usar 'awk' para acoplar una salida de un programa con la entrada de otro que necesite un formato muy distinto. En definitiva vamos a explicar solo una pequeña parte de este potente lenguaje pero comprobará su gran utilidad muy pronto.

Forma de uso
'awk' suele estar instalado en la mayoría de los sistemas ya que su uso suele ser necesario. Por eso en Linux suele encontrarse entre los paquetes básicos del sistema en todas las distribuciones.

Se puede usar de varias formas. Tenemos que pasar a 'awk' el texto del programa, y los datos. El primero se puede pasar bien como argumento o indicando -f nombre del fichero que contiene el texto del programa. La entrada se puede pasar dando el nombre del fichero de entrada como último argumento o en caso contrario lo tomará por la entrada estándar.

$ ## Generamos en /tmp un par de ficheros
$ echo -e "\n"  > /tmp/echo.out 
$ echo '{  print "Hola mundo" }' > /tmp/ejemplo1.awk 
$ ## Ejecutaremos el mismo programa de 4 formas distintas
$ echo -e "\n" | awk '{  print "Hola mundo" }'
 Hola mundo
 Hola mundo
$ awk '{  print "Hola mundo" }' /tmp/echo.out
 Hola mundo
 Hola mundo
$ echo -e "\n" | awk -f /tmp/ejemplo1.awk
 Hola mundo
 Hola mundo
$ awk -f /tmp/ejemplo1.awk /tmp/echo.out
 Hola mundo
 Hola mundo

El programa que acabamos de utilizar imprimirá el literal "Hola mundo" a cada línea de datos que procese. En este caso usamos solo un par de líneas vacías como entrada de datos.

Vamos a localizar el binario de 'awk'

$ whereis awk
 /usr/bin/awk

Vamos a suponer que en su sistema se encuentre también en '/usr/bin'. Puesto que awk es un lenguaje interpretado perfectamente legible también podemos decir que los programas de awk son script. Para poder usarlos directamente podemos añadir una primera línea con número mágico y poner permiso de ejecución.

$ echo '#!/usr/bin/awk -f' > /tmp/ejemplo2.awk
$ echo '{  print "Hola mundo" }' >> /tmp/ejemplo2.awk
$ chmod +x /tmp/ejemplo2.awk
$ echo -e "\n" | /tmp/ejemplo2.awk
 Hola mundo
 Hola mundo

Estructura de un programa awk
Un programa 'awk' puede tener tres secciones distintas.

El primer ejemplo que vimos anteriormente ("Hola mundo") solo tenía una de las tres partes. Concretamente era la parte central ya que no pusimos ninguna de las palabras reservadas BEGIN o END.

Vamos a poner ahora un ejemplo con las tres partes. Edite un fichero con nombre '/tmp/3partes.awk'

BEGIN { print "Erase una vez..." }
{ print "...y entonces bla, bla, bla ..." }
END { print "...y colorín colorado este cuento se ha acabado." }

Ejecutelo con:

$ echo -e "\n\n\n" | awk -f /tmp/3partes.awk
çAma Erase una vez...
...y entonces bla, bla, bla ...
...y entonces bla, bla, bla ...
...y entonces bla, bla, bla ...
...y entonces bla, bla, bla ...
...y colorín colorado este cuento se ha acabado.

Es importante que comprenda que la parte central se ejecutará tantas veces como líneas de datos existan. En nuestro ejemplo son cuatro líneas generadas por 'echo -e "\n\n\n" '. En cambio las partes 'BEGIN { ... }' y 'END { ... }' se ejecutan una sola vez. La primera antes de procesar la primera línea y la última después de procesar la última línea.

Los comentarios en 'awk' comienzan con un '#' y terminan al final de la línea.

Expresiones regulares
Algunas veces los datos pueden venir con algunas lineas que no interesa procesar o que se deben procesar de forma distinta. Podemos usar una expresión regular delimitada por el carácter '/' para seleccionar una acción especial. Vamos a editar otro ejemplo que llamaremos '/tmp/expreg.awk':

BEGIN { print "Erase una vez..." }
/^$/ { print "Linea vacía" }
/[0-9]+/ { print "Tiene un número" }
/\.$/ { print "Termina con punto" }
# Esto es un comentario
{ print "--------------------------------------" }
END { print "...y colorín colorado este cuento se ha acabado." }

Ahora editamos un segundo fichero '/tmp/expreg.dat':

Línea número 1.
Línea número 2

....
Fin de los datos

Ahora ejecute lo siguiente:

$ awk -f /tmp/expreg.awk /tmp/expreg.dat
 Erase una vez...
 Tiene un número
 Termina con punto
 --------------------------------------
 Tiene un número
 --------------------------------------
 Linea vacía
 --------------------------------------
 Termina con punto
 --------------------------------------
 --------------------------------------
 ...y colorín colorado este cuento se ha acabado.

Vemos que cada línea de datos puede cumplir más de una regla y que cuando no ponemos una expresión regular siempre se ejecutará la acción. En este caso todas las líneas provocan la escritura de una línea de guiones '--------------------------------------'.

El uso de expresiones regulares puede ayudarnos a eliminar cabeceras, líneas vacías o incompletas o cosas así que no deseamos procesar.

Delimitadores de campos
No hemos tratado aun los campos de una línea. Una línea que tenga distintos campos debe usar alguna secuencia para delimitar los campos entre si.

Lo mismo para definir un delimitador que en cualquier otro caso donde se usen cadenas de caracteres podemos encontrarnos la necesidad de usar caracteres especiales que no pueden ser introducidos directamente. Para ello existen determinadas secuencias que empiezan por el carácter '\' y que tienen significado especial.

Caracteres de escape
\a Produce un pitido en el terminal
\b Retroceso
\f Salto de página
\n Salto de línea
\r Retorno de carro
\t Tabulador horizontal
\v Tabulador vertical
\ddd Carácter representado en octal por 'ddd'
\xhex Carácter representado en hexadecimal por 'hex'
\c Carácter 'c'

El último caso se usa para eliminar el significado especial de un carácter en determinadas circunstancias. Por ejemplo para usar un '+' o un '-' en una expresión regular usaríamos '\+' o '\-'

Podemos elegir un solo carácter para separar campos. Hay ficheros de configuración como /etc/passwd, /etc/group, que usan un solo carácter para delimitar los campos. Por ejemplo los dos puntos ':' , el blanco '\ ', la coma ',' el tabulador '\t' etc...

'awk' permite usar como delimitador más de un carácter. Para ello se asignará a la variable 'FS' una cadena de caracteres que contenga una expresión regular . Por ejemplo para usar como delimitador el carácter ':' habría que incluir 'BEGIN { FS = ":" }'

Si no se especifica ningún delimitador se asumirá que los campos estarán delimitados por uno o más blancos o tabuladores consecutivos lo cual se expresa como "[\ \t]+". Las expresiones regulares ya fueron estudiadas en un capítulo especial. El carácter '\' debe usarse para escapar cualquier carácter con significado especial en una expresión regular y algunos caracteres normales precedidos de '\' se usan para representar caracteres especiales. '\t' es el tabulador.

En 'awk' se usa $1 para referenciar el campo 1, $2 para referenciar el campo 2, etc... y para referenciar el registro completo usaremos $0.

Edite el siguiente fichero '/tmp/delim1.awk'

{ print  "+", $1, "+", $2, "+", $3, "+", $4, "+" }

$1, $2, $3, y $4 representan a los campos 1, 2, 3, y 4 respectivamente. Edite el siguiente fichero de datos '/tmp/delim1.dat'

aaa bbb ccc 	 	ddd 	 	eee
111 222 333 444

En la primera línea debe introducir un blanco para separar los primeros blancos y una secuenciencia de ', , , ' para separar los dos últimos campos. Es importante que lo edite de esta forma porque el resultado de los ejemplos podría variar.

Ahora ejecute lo siguiente:

$ awk -f /tmp/delim1.awk /tmp/delim1.dat
+ aaa + bbb + ccc + ddd +
+ 111 + 222 + 333 + 444 +

Edite el siguiente fichero '/tmp/delim0.awk'

{ print  "+", $3, "+", $4, "+", $1, "+", $2, "+" }

Ahora ejecute lo siguiente:

$ awk -f /tmp/delim0.awk /tmp/delim1.dat
+ ccc + ddd + aaa + bbb +
+ 333 + 444 + 111 + 222 +

Con ello hemos conseguido variar el orden de aparición de los campos, pero todavía no hemos especificado ningún delimitador. Por ello hemos asumido el delimitador por defecto. (uno o más blancos y tabuladores). Para especificar un delimitador distinto tenemos que asignar su valor a la variable FS y además tenemos que hacerlo antes de leer el primero registro por lo cual se incluirá la instrucción en la sección inicial precedida de BEGIN.

Edite el siguiente fichero '/tmp/delim2.awk'

BEGIN { FS = "\ " }
{ print  "+", $1, "+", $2, "+", $3, "+", $4, "+" }

Estamos definiendo un único carácter blanco como separador. Ahora ejecute lo siguiente:

$ awk -f /tmp/delim2.awk /tmp/delim1.dat
+ aaa + bbb + ccc +      +
+ 111 + 222 + 333 + 444 +

Vamos a cambiar de delimitador. Edite el siguiente fichero '/tmp/delim3.awk'

BEGIN { FS = "\t" }
{ print  "+", $1, "+", $2, "+", $3, "+", $4, "+" }

Estamos definiendo un único carácter tabulador como separador. Ahora ejecute lo siguiente:

$ awk -f /tmp/delim3.awk /tmp/delim1.dat
+ aaa bbb ccc  +   + ddd  +   +
+ 111 222 333 444 +  +  +  +

Selección de registros por campo
Vamos a editar un fichero que simulará la salida de datos obtenida desde una base de datos relacional. Usaremos estos datos en varios ejemplos. Puede corresponder a una contabilidad de un alquiler de un piso. Lo llamaremos 'contabil.dat'.

     fecha|concepto|importe
----------+--------+-------
01-01-1999|-       |     96
16-12-1999|AGUA    | -14650
05-01-2000|LUZ     | -15797
24-01-2000|GAS     | -34175
27-01-2000|INGRESO | 141200
01-02-2000|MENS    | -96092
25-02-2000|LUZ     | -12475
01-03-2000|MENS    | -96092
06-03-2000|INGRESO | 101300
01-04-2000|MENS    | -96092
06-04-2000|AGUA    | -15859
07-04-2000|INGRESO | 134000
01-05-2000|MENS    | -98975
02-05-2000|LUZ     | -11449
09-05-2000|INGRESO |  95000
23-05-2000|GAS     | -21428
25-05-2000|GAS     | -16452
01-06-2000|MENS    | -98975
07-06-2000|INGRESO | 130000
01-07-2000|MENS    | -98975
04-07-2000|LUZ     | -12403
07-07-2000|AGUA    |  -5561
10-07-2000|INGRESO |  99000
24-07-2000|GAS     | -11948
01-08-2000|MENS    | -98975
10-08-2000|INGRESO | 122355
04-09-2000|LUZ     | -12168
10-09-2000|INGRESO | 129000
19-09-2000|AGUA    | -10529
28-09-2000|GAS     |  -2620
01-10-2000|MENS    | -98975
10-10-2000|INGRESO | 112000
(32 rows)

Lo primero que vemos es que tiene una cabecera de dos líneas inútiles y un final también inútil. Podemos asegurar que las líneas que deseamos procesar cumplirán un patrón de dos números guión dos números guión cuatro números y línea vertical. Vamos a editar un programa que llamaremos 'contabil1.awk'

BEGIN { FS="\|" }
/[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9][0-9][0-9]\|/  { 
print NR, ", ", $1, ", ", $2, ", ", $3
}

Vamos a ejecutar este ejemplo y vamos a ver su salida

$ awk -f contabil1.awk < contabil.dat
3 ,  01-01-1999 ,  -        ,       96
4 ,  16-12-1999 ,  AGUA     ,   -14650
5 ,  05-01-2000 ,  LUZ      ,   -15797
6 ,  24-01-2000 ,  GAS      ,   -34175
7 ,  27-01-2000 ,  INGRESO  ,   141200
8 ,  01-02-2000 ,  MENS     ,   -96092
9 ,  25-02-2000 ,  LUZ      ,   -12475
10 ,  01-03-2000 ,  MENS     ,   -96092
11 ,  06-03-2000 ,  INGRESO  ,   101300
12 ,  01-04-2000 ,  MENS     ,   -96092
13 ,  06-04-2000 ,  AGUA     ,   -15859
14 ,  07-04-2000 ,  INGRESO  ,   134000
15 ,  01-05-2000 ,  MENS     ,   -98975
16 ,  02-05-2000 ,  LUZ      ,   -11449
17 ,  09-05-2000 ,  INGRESO  ,    95000
18 ,  23-05-2000 ,  GAS      ,   -21428
19 ,  25-05-2000 ,  GAS      ,   -16452
20 ,  01-06-2000 ,  MENS     ,   -98975
21 ,  07-06-2000 ,  INGRESO  ,   130000
22 ,  01-07-2000 ,  MENS     ,   -98975
23 ,  04-07-2000 ,  LUZ      ,   -12403
24 ,  07-07-2000 ,  AGUA     ,    -5561
25 ,  10-07-2000 ,  INGRESO  ,    99000
26 ,  24-07-2000 ,  GAS      ,   -11948
27 ,  01-08-2000 ,  MENS     ,   -98975
28 ,  10-08-2000 ,  INGRESO  ,   122355
29 ,  04-09-2000 ,  LUZ      ,   -12168
30 ,  10-09-2000 ,  INGRESO  ,   129000
31 ,  19-09-2000 ,  AGUA     ,   -10529
32 ,  28-09-2000 ,  GAS      ,    -2620
33 ,  01-10-2000 ,  MENS     ,   -98975
34 ,  10-10-2000 ,  INGRESO  ,   112000

Podemos apreciar varias cosas. NR es una variable del sistema que toma el valor del número de registro que se está procesando. Podemos ver que las dos primeras líneas y la última han sido descartadas. También vemos que las primeras líneas usan un solo dígito para el número de registro y luego usan dos dígitos. Esto que las columnas no queden alineadas.

Vamos a modificar el programa para que muestre los registros completos ($0) cuando no se cumpla la condición anterior. Para ello editaremos un fichero que llamaremos 'contabdescarte.awk'.

BEGIN { FS="\|" }
! /[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9][0-9][0-9]\|/  { 
print NR, $0
}

Vamos a ejecutar este ejemplo y vamos a ver su salida

$ awk -f contabdescarte.awk < contabil.dat

1      fecha|concepto|importe
2 ----------+--------+-------
35 (32 rows)

Formato de salida con printf
Para imprimir con formato usaremos 'printf' en lugar de 'print'. printf se usa en varios lenguajes. El primer argumento de esta función debe de ser una cadena de caracteres que contenga el formato de salida deseado para la salida. Los formatos de cada dato se expresan mediante unas directivas que empiezan con el carácter '%' y debe de existir en dicha cadena tantas directivas como datos separados por coma a continuación de la cadena de formato.

Hay que tener en cuenta que en 'awk' la concatenación de cadenas se usa poniendo una cadena a continuación de otra separada por blancos. Por ejemplo:
# cad = "(unodos)" cad = "uno" "dos" ; cad = "(" cad ")"

Especificación de formato de datos para 'printf'
%c Carácter ASCII
%d Entero representado en decimal
%e Coma flotante (exponente = e[+-]dd)
%E Coma flotante (exponente = E[+-]dd)
%f Coma flotante sin exponente
%g Equivale al más corto de los formatos 'e' o 'f'
%G Equivale al más corto de los formatos 'E' o 'F'
%o Entero representado en octal
%s Cadena de caracteres
%x Entero representado en hexadecimal con minúsculas
%X Entero representado en hexadecimal con mayúsculas
%% Carácter '%'

En estos formatos se puede intercalar inmediatamente a continuación del '%' primero un signo '+' o un '-' que son opcionales y significan respectivamente alineación a la derecha o a la izquierda. En segundo lugar y de forma igualmente opcional se puede intercalar un número para indicar un ancho mínimo. (Si el dato ocupa más que el dato especificado se muestra el dato completo haciendo caso omiso de la indicación de anchura). En el caso de coma flotante se puede indicar el ancho total del campo y la precisión (anchura) de la parte decimal.

Veamos unos pocos ejemplos.

$ echo  | awk '{  print "Hola mundo" }'

Hola mundo
$ echo  | awk '{  printf "Hola %s\n", "mundo" }'

Hola mundo
$ echo  | awk '{  printf "#%d#%s#\n", 77, "mundo" }'

#77#mundo#
$ echo  | awk '{  printf "#%10d#%10s#\n", 77, "mundo" }'

#        77#     mundo#
$ echo  | awk '{  printf "#%-10d#%-10s#\n", 77, "mundo" }'

#77        #mundo     #
$ echo  | awk '{  printf "#%+4d#%+4s#\n", 77, "mundo" }'

# +77#mundo#
$ echo  | awk '{  printf "#%04d#%+4s#\n", 77, "mundo" }'

#0077#mundo#
$ echo  | awk '{  printf "#%010.5f#%E#%g\n", 21.43527923, 21.43527923, 21.43527923  }'

#0021.43528#2.143528E+01#21.4353
$ echo  | awk '{  printf "#%10.5f#%E#%g\n", 2140000, 2140000, 2140000  }'

#2140000.00000#2.140000E+06#2.14e+06

Practique un poco investigando con más detalle el funcionamiento de estos formatos.

Uso de variables operadores y expresiones
En 'awk' podemos usar toda clase de expresiones presentes en cualquier lenguaje. Cualquier identificador que no corresponda con una palabra reservada se asumirá que es una variable. Para asignar un valor se usa el operador '='

Vamos a editar un fichero que llamaremos 'ejemplexpr.awk' con algunas expresiones aritméticas.

{
contador = 0;  # Pone a cero la variable contador
contador ++;   # Incrementa en 1 la variable contador
contador +=10; # Incrementa en 10 la variable contador.
contador *=2   # Multiplica por 2 la variable contador
print contador
contador = ( 10 + 20 ) / 2 ;
print contador
contador = sqrt ( 25 ) ; # Raiz cuadrada de 25
print contador
}

Lo ejecutamos y observamos el resultado.

$ echo | awk -f ejemplexpr.awk

22
15
5

No podemos explicar en detalle todo el lenguaje 'awk'. Se trata de que comprenda su utilidad y de que sea capaz de utilizarlo para determinadas tareas en las cuales resulta extremadamente útil.

Algunas expresiones parecen inspiradas en el lenguaje C. Otras parece que han servido de inspiración para el lenguaje Perl. En realidad muchos lenguajes usan expresiones parecidas.

Por ello vamos a resumir en forma de tabla una serie de elementos que intervienen en las expresiones que 'awk' es capaz de manejar. Pero no vamos a explicar en detalle cada cosa. En lugar de eso daremos una descripción resumida y procuraremos que los ejemplos posteriores tengan un poco de todo.

Operadores aritméticos
+ Suma
- Resta
* Multiplicación
/ División
% Módulo (resto)
^ Potenciación
Operadores de asignación.
var = expr Asignación
var ++ Incrementa la variable en una unidad
var -- Decrementa la variable en una unidad
var += expr_aritm Incrementa la variable en cierta cantidad
var -= expr_aritm Decrementa la variable en cierta cantidad
var *= expr_aritm Multiplica la variable por cierta cantidad
var /= expr_aritm Divide la variable por cierta cantidad
var %= expr_aritm Guarda en la variable el resto de su división por cierta cantidad
var ^= expr_aritm Eleva el valor de la variable en cierta cantidad
Operadores lógicos y de relación.
expr_aritm == expr_aritm Comparación de igualdad
expr_aritm != expr_aritm Comparación de desigualdad
expr_aritm < expr_aritm Comparación menor que
expr_aritm > expr_aritm Comparación mayor que
expr_aritm <= expr_aritm Comparación menor igual que
expr_aritm >= expr_aritm Comparación mayor igual que
expr_cad ~ expr_regular Se ajusta al patrón
expr_cad !~ expr_regular No se ajusta al patrón
expr_logica || expr_logica Operador lógico AND (Y)
expr_logica && expr_logica Operador lógico OR (O)
! expr_logica Operador lógico NOT (NO)
Funciones aritméticas.
atan2( y, x) Retorna el arco-tangente de y/x en radianes
cos(x) Retorna el coseno de x en radianes
exp(x) Retorna el exponencial de x (e^x)
int(x) Retorna el valor entero de x truncado la parte decimal
log(x) Retorna el logaritmo neperiano de x
rand() Retorna un valor seudo aleatorio comprendido entre 0 y 1
sin(x) Retorna el seno de x en radianes
sqrt(x) Retorna la raiz cuadrada de x
srand(x) Inicializa la semilla para generar números pseudoaleatorios
Funciones para usar con cadenas de caracteres
gsub(r, s, t) Sustituye 's' globalmente en todo 't' cada vez que se encuentre un
patrón ajustado a la expresión regular 'r'. Si no se proporciona 't'
se toma $0 por defecto.
Devuelve el número de sustituciones realizado.
index(cadena, subcadena) Retorna la posición de la 'subcadena' en 'cadena' (Primera posición = 1)
length(cadena) Devuelve la longitud de la 'cadena'. Tomará $0 por defecto si no se
proporciona 'cadena'
split(cadena, array, sep) Parte 'cadena' en elementos de 'array' utilizando 'sep' como separador.
Si no se proporciona 'sep' se usará FS. Devuelve el número de elementos
del array
sub(r, s, t) Sustituye 's' en 't' la primera vez que se encuentre un patrón
ajustado a la expresión regular 'r'. Si no se proporciona 't' se toma $0
por defecto.
Devuelve 1 si tiene éxito y 0 si falla
substr(cadena, beg, len) Devuelve una subcadena de 'cadena' que empieza en 'beg' con una longitud
'len'. Si no se proporciona longitud devuelve hasta el final de la cadena
desde 'beg'
tolower(cadena) Pasa a minúsculas
toupper(cadena) Pasa a mayúsculas
Algunas otras funciones
match(cadena, expr_reg) Indica si 'cadena' se ajusta o no a la expresión regular 'expr_reg'
system(comando)
sprintf(formato [, expr-list] ) Para obtener salida con formato.

Computo con registros

Vamos a modificar el programa 'contabil1.awk' para procesar solo los registros de consumo de luz, vamos a mejorar el formato de salida, vamos a incluir un contador de registros seleccionados, un contador de consumo de luz, y al final obtendremos el consumo total y el consumo promedio de luz. Lo llamaremos 'contabil2.awk'

BEGIN { 
   FS="\|" ; 
   cont_reg_luz=0; 
   cont_importe_luz=0;
   }
   
$2 ~ /LUZ/  {
   cont_reg_luz = cont_reg_luz + 1 ;
   cont_importe_luz = cont_importe_luz + $3 ;
   printf ("%3d, %3d, %s, %s, %s, %10d\n", NR, cont_reg_luz, $1, $2, $3, cont_importe_luz);
}
END {
   printf ("Consumo promedio = %d\n", cont_importe_luz / cont_reg_luz) ;
}

Vamos a ejecutar este ejemplo y vamos a ver su salida

$ awk -f contabil2.awk < contabil.dat
  5,   1, 05-01-2000, LUZ     ,  -15797,     -15797
  9,   2, 25-02-2000, LUZ     ,  -12475,     -28272
 16,   3, 02-05-2000, LUZ     ,  -11449,     -39721
 23,   4, 04-07-2000, LUZ     ,  -12403,     -52124
 29,   5, 04-09-2000, LUZ     ,  -12168,     -64292
Consumo promedio = -12858

Los datos que estamos usando para el ejemplo están ordenados por fechas. Vamos a obtener un informe con un campo más que será el saldo de la cuenta. Para ello editamos un fichero que llamaremos 'contabil3.awk'.

BEGIN { 
   FS="\|" ; 
   cont_importe=0;
   }
   
/[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9][0-9][0-9]\|/  {
   cont_importe = cont_importe + $3 ;
   printf ("%3d, %s, %s, %s, %10d\n", NR,  $1, $2, $3, cont_importe);
}

Vamos a ejecutar este ejemplo y vamos a ver su salida

$ awk -f contabil3.awk < contabil.dat
  3, 01-01-1999, -       ,      96,         96
  4, 16-12-1999, AGUA    ,  -14650,     -14554
  5, 05-01-2000, LUZ     ,  -15797,     -30351
  6, 24-01-2000, GAS     ,  -34175,     -64526
  7, 27-01-2000, INGRESO ,  141200,      76674
  8, 01-02-2000, MENS    ,  -96092,     -19418
  9, 25-02-2000, LUZ     ,  -12475,     -31893
 10, 01-03-2000, MENS    ,  -96092,    -127985
 11, 06-03-2000, INGRESO ,  101300,     -26685
 12, 01-04-2000, MENS    ,  -96092,    -122777
 13, 06-04-2000, AGUA    ,  -15859,    -138636
 14, 07-04-2000, INGRESO ,  134000,      -4636
 15, 01-05-2000, MENS    ,  -98975,    -103611
 16, 02-05-2000, LUZ     ,  -11449,    -115060
 17, 09-05-2000, INGRESO ,   95000,     -20060
 18, 23-05-2000, GAS     ,  -21428,     -41488
 19, 25-05-2000, GAS     ,  -16452,     -57940
 20, 01-06-2000, MENS    ,  -98975,    -156915
 21, 07-06-2000, INGRESO ,  130000,     -26915
 22, 01-07-2000, MENS    ,  -98975,    -125890
 23, 04-07-2000, LUZ     ,  -12403,    -138293
 24, 07-07-2000, AGUA    ,   -5561,    -143854
 25, 10-07-2000, INGRESO ,   99000,     -44854
 26, 24-07-2000, GAS     ,  -11948,     -56802
 27, 01-08-2000, MENS    ,  -98975,    -155777
 28, 10-08-2000, INGRESO ,  122355,     -33422
 29, 04-09-2000, LUZ     ,  -12168,     -45590
 30, 10-09-2000, INGRESO ,  129000,      83410
 31, 19-09-2000, AGUA    ,  -10529,      72881
 32, 28-09-2000, GAS     ,   -2620,      70261
 33, 01-10-2000, MENS    ,  -98975,     -28714
 34, 10-10-2000, INGRESO ,  112000,      83286

Sentencias condicionales y bucles

'awk' es un lenguaje muy completo y no podía faltar las sentencias de ejecución condicional y de ejecución en bucle.

Algunos de los conceptos que vamos a comentar ya los hemos visto cuando hablamos de la programación en bash y no vamos a explicar con demasiado detalle cada tipo de sentencia. La sintaxis que usa awk no se parece a la sintaxis que ya hemos visto para bash. Se parece más a la sintaxis del lenguaje C. De todas formas los conceptos ya nos resultan familiares y usaremos algunos ejemplos para ilustrarlos.

Empezaremos describiendo la sintaxis de cada tipo de sentencia. Denominaremos acción a una sentencia simple o a una sentencia compuesta de la forma '{ sentencia1 ; sentencia2 ; ... }'

Sentencia condicional 'if'

if ( expresión_lógica ) accion1 [ else accion2 ]

Sentencia condicional con los operadores '?' y ':'
expresion_lógica ? accion1 : accion2

Bucle 'while'
while ( expresión_lógica ) accion

Bucle 'do' 'while'
do accion while ( expresión_lógica )

Bucle 'for'
for ( inicializar_contador ; comprobar_contador ; modificar_contador ) accion

Dentro de los bucles podemos usar break para forzar la salida de un bucle o continue para saltar a la siguiente iteración.

Veremos de momento tan solo un ejemplo para la sentencia condicional 'if'.

Edite el siguiente fichero que llamaremos 'contabil4.awk'

BEGIN { FS="\|" ; }
   
/[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9][0-9][0-9]\|/  {
   if ( $3 >= 0)  {
       printf ("%3d, %s, %s, %s\n", NR,  $1, $2, $3);
   }
}

Vamos a ejecutar este ejemplo y vamos a ver su salida

$ awk -f contabil4.awk < contabil.dat
  3, 01-01-1999, -       ,      96
  7, 27-01-2000, INGRESO ,  141200
 11, 06-03-2000, INGRESO ,  101300
 14, 07-04-2000, INGRESO ,  134000
 17, 09-05-2000, INGRESO ,   95000
 21, 07-06-2000, INGRESO ,  130000
 25, 10-07-2000, INGRESO ,   99000
 28, 10-08-2000, INGRESO ,  122355
 30, 10-09-2000, INGRESO ,  129000
 34, 10-10-2000, INGRESO ,  112000

Pasar valores al script awk
En ocasiones puede resultar interesante poder pasar algún valor al script awk. Vamos a modificar el programa anterior para que muestre los registros con un importe superior a un valor que pasaremos por parámetro.

Edite el siguiente fichero que llamaremos 'contabil5.awk'

BEGIN { FS="\|" ; }
   
/[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9][0-9][0-9]\|/  {
   if ( $3 >= minimo && $3 <= maximo )  {
       printf ("%3d, %s, %s, %s\n", NR,  $1, $2, $3);
   }
}

Vamos a ejecutar este ejemplo pasando y vamos a ver su salida

$ awk -f contabil5.awk minimo=100000 maximo=120000 < contabil.dat
 11, 06-03-2000, INGRESO ,  101300
 34, 10-10-2000, INGRESO ,  112000

Hay que advertir que el paso de parámetros equivale a definir una variable y a asignar un valor pero esto valor no será accesible hasta después de leer el primer registro. Si el valor pasado como parámetro tuviera que ser accesible en la sección BEGIN habría que usar la opción -v previo al paso del parámetro.

Repetiremos el ejemplo pasando el delimitador del registro que usaremos en la sección BEGIN.

Edite el siguiente fichero que llamaremos 'contabil6.awk'

BEGIN { FS = delimitador ; }
   
/[0-9][0-9]\-[0-9][0-9]\-[0-9][0-9][0-9][0-9]\|/  {
   if ( $3 >= minimo && $3 <= maximo )  {
       printf ("%3d, %s, %s, %s\n", NR,  $1, $2, $3);
   }
}

Vamos a ejecutar este ejemplo pasando valores y vamos a ver su salida

$ awk -f contabil6.awk  minimo=100000 maximo=120000 deliminador='|' < contabil.dat

Vemos que no hemos obtenido el resultado esperado.

Vamos a volver a ejecutar este ejemplo pasando el valor del delimitador con la opción -v y vamos a ver su nueva salida

$ awk -v delimitador='|' -f contabil6.awk minimo=100000 maximo=120000 < contabil.dat
 11, 06-03-2000, INGRESO ,  101300
 34, 10-10-2000, INGRESO ,  112000

Declaración de funciones
Como es lógico 'awk' permite la declaración de funciones. Normalmente se recurre a implementar una función cuando necesitamos una funcionalidad que el lenguaje no proporciona de forma predefinida o cuando queremos estructurar el código de un programa grande en fragmentos más pequeños y por tanto más manejables.

La sintaxis es muy sencilla.


function nombre_de_la_función ( lista_de_parámetros ) {
     sentencias
}  

Por ejemplo para declarar una función que retorne un número aleatorio entre 1 y 6.

Edite un fichero con nombre 'dado.awk'.

function aleatorio ( minimo, maximo ){
    return ( ( ( maximo - minimo + 1 ) * rand () ) + minimo ) ;
}

END{
	for (i=0; i<20; i++){
		printf ("%3d) Entre 1 y 6 = %3d    Entre 5 y 15 =%3d\n", 
		         i, aleatorio (1, 6),  aleatorio(5, 15));
	}
}

Ahora lo ejecutamos

$ echo | awk -f dado.awk
  0) Entre 1 y 6 =   5    Entre 5 y 15 = 12
  1) Entre 1 y 6 =   6    Entre 5 y 15 =  7
  2) Entre 1 y 6 =   6    Entre 5 y 15 =  7
  3) Entre 1 y 6 =   5    Entre 5 y 15 = 13
  4) Entre 1 y 6 =   3    Entre 5 y 15 =  8
  5) Entre 1 y 6 =   3    Entre 5 y 15 =  6
  6) Entre 1 y 6 =   4    Entre 5 y 15 =  7
  7) Entre 1 y 6 =   6    Entre 5 y 15 =  7
  8) Entre 1 y 6 =   5    Entre 5 y 15 =  6
  9) Entre 1 y 6 =   3    Entre 5 y 15 = 10
 10) Entre 1 y 6 =   6    Entre 5 y 15 = 14
 11) Entre 1 y 6 =   5    Entre 5 y 15 = 10
 12) Entre 1 y 6 =   6    Entre 5 y 15 = 11
 13) Entre 1 y 6 =   4    Entre 5 y 15 = 12
 14) Entre 1 y 6 =   5    Entre 5 y 15 = 15
 15) Entre 1 y 6 =   2    Entre 5 y 15 =  9
 16) Entre 1 y 6 =   1    Entre 5 y 15 =  9
 17) Entre 1 y 6 =   3    Entre 5 y 15 = 14
 18) Entre 1 y 6 =   2    Entre 5 y 15 = 14
 19) Entre 1 y 6 =   2    Entre 5 y 15 =  7

Función system
Esta es una función fácil de usar que nos permite ejecutar un comando del sistema operativo. En caso de éxito retorna 0, y en caso de error retornará un valor distinto de cero.

$ awk ' BEGIN { if (system("ls") !=0) printf ("Error de ejecución\n"); }'

Por ejemplo si quisiéramos verificar la existencia de un fichero almacenado en la variable 'nombre_fich' tendríamos que hacer

if (system("test -r " nombre_fich)) {
	fprintf ("%s no encontrado\n", nombre_fich);
}

La función getline y otras funciones avanzadas
Este es es un apartado en el que más que explicar cosas nos vamos a limitar a mencionar ciertas posibilidades. No podemos dedicar demasiado espacio a este tipo de cuestiones avanzadas pero si con lo que en este apartado contemos conseguimos ponerle los dientes largos nos daremos por satisfechos aunque no entienda una palabra.

En primer lugar hay que advertir que 'getline' que al igual que otras funciones devuelve un valor pero su sintaxis no es una típica sintaxis de función. No se usa como 'getline()' sino como una sentencia.

Esta función retorna 1 si lee una línea, 0 si alcanza el fin de la entrada de datos y -1 si se produce un error.

Usada simplemente como 'getline' sin nada más lee la siguiente linea de la entrada asignando $0 y desglosando los campos en $1, $2, $3, etc..

Se puede asignar el valor completo de la línea leída a una variable con 'getline variable' evitando de esta forma alterar el valor de $0.

Se puede leer de un fichero usando el operador redirección. 'getline < "fichero"'. Se puede simbolizar la entrada estándar como "-"

Se puede leer desde un pipe. '"whoami" | getline usuario'.

Edite un fichero llamado 'tipo_usuario.awk'.

BEGIN {
"whoami" | getline usuario
 if ( usuario ~ /root/ ) { 
     printf ("Soy superusuario\n"); 
 } 
 else{
    printf ("Soy usuario normal\n");
 }
}

Ejecute lo con

$ awk -f tipo_usuario.awk

No pretendemos con este sencillo ejemplo que sea capaz de usar estas funciones. El manejo de estas redirecciones es complicado y en ocasiones se hace necesario forzar el cierre de una entrada o de un pipe. Para eso existe la función 'close'. Se usa haciendo 'close ("fichero")' o 'close ("whoami")'.

Por el momento nos conformamos con lo explicado y veremos un poco más adelante el uso de getline tomando la entrada de un fichero cuando expliquemos los arrays asociativos.

Arrays
Los array permiten el almacenamiento de una serie de elementos que pueden ser accedidos mediante un índice. En realidad los arrays de awk son más potentes que los arrays que vimos cuando estudiamos la programación de la bourne-shell donde los índices de un array eran siempre números enteros. Vamos a usar en primer lugar los arrays de esta forma. Es decir nos vamos a limitar en los primeros ejemplos a usar números enteros como índices.

Vamos a usar awk para procesar la salida obtenida con 'ps'. Primero vamos a suponer que obtenemos un listado completo de los procesos del sistema en formato largo. Si intenta realizar este ejemplo obtendrá un resultado necesariamente diferente.

$ ps axl > ps-axl.out ; cat ps-axl.out
 FLAGS   UID   PID  PPID PRI  NI   SIZE   RSS WCHAN       STA TTY TIME COMMAND
   100     0     1     0   0   0    756     0 do_select   SW  ?   0:03 (init)
    40     0     2     1   0   0      0     0 bdflush     SW  ?   0:18 (kflushd)
    40     0     3     1   0   0      0     0 kupdate     SW  ?   0:18 (kupdate)
   840     0     4     1   0   0      0     0 kpiod       SW  ?   0:00 (kpiod)
   840     0     5     1   0   0      0     0 kswapd      SW  ?   0:15 (kswapd)
   140     0   186     1   0   0    900   200 do_select   S   ?   0:00 /sbin/sys
   140     0   188     1   0   0   1016     0 do_syslog   SW  ?   0:00 (klogd)
   140     1   193     1   0   0    780     0 do_select   SW  ?   0:00 (portmap)
   140     0   195     1   0   0    860     0 do_select   SW  ?   0:00 (inetd)
   140     0   200     1   0   0    764   108 nanosleep   S   ?   0:00 /usr/sbin
   140     0   210     1   0   0    908     0 do_select   SW  ?   0:00 (lpd)
    40    31   226     1   0   0   3784     0 do_select   SW  ?   0:00 (postmast
   140     0   237     1   5   0   1728   316 do_select   S   ?   0:00 sendmail:
   140     0   241     1   0   0   1292   184 do_select   S   ?   0:01 /usr/sbin
    40     0   244     1   0   0   1544    56 do_select   S   ?   0:00 /usr/bin/
    40     1   254     1   0   0    840    96 nanosleep   S   ?   0:00 /usr/sbin
    40     0   257     1   5   0    860   164 nanosleep   S   ?   0:00 /usr/sbin
   140     0   262     1   0   0   1780    60 do_select   S   ?   0:07 /usr/sbin
   100     0   268     1   0   0   1964   616 read_chan   S    1  0:00 -bash 
   100     0   269     1   0   0    836     0 read_chan   SW   2  0:00 (getty)
   100  1001   270     1   0   0   2096   724 wait4       S    3  0:00 -bash 
   100     0   271     1   0   0    836     0 read_chan   SW   4  0:00 (getty)
   100     0   272     1   0   0    836     0 read_chan   SW   5  0:00 (getty)
   100  1001   273     1   0   0   2088  1408 wait4       S    6  0:00 -bash 
   140    33   274   262   0   0   1792     0 wait_for_co SW  ?   0:00 (apache)
   140    33   275   262   0   0   1792     0 flock_lock_ SW  ?   0:00 (apache)
   140    33   276   262   0   0   1792     0 flock_lock_ SW  ?   0:00 (apache)
   140    33   277   262   0   0   1792     0 flock_lock_ SW  ?   0:00 (apache)
   140    33   278   262   0   0   1792     0 flock_lock_ SW  ?   0:00 (apache)
     0  1001   916   270   0   0   3536  1640 do_select   S    3  0:00 vi awk1.d
     0  1001  1029   273   0   0   1916   668 wait4       S    6  0:00 xinit /ho
   100     0  1034  1029  12   0   8824  3280 do_select   S   ?   0:02 X :0 -bpp
     0  1001  1037  1029   0   0   4620  2748 do_select   S    6  0:01 mwm 
    40  1001  1042  1037   0   0   1728   924 wait4       S    6  0:00 bash /hom
    40  1001  1045  1037   0   0   1728   924 wait4       S    6  0:00 bash /hom
     0     0  1050  1042   0   0   2976  1872 do_select   S    6  0:00 xterm -ls
     0  1001  1058  1045   0   0   2320  1220 do_select   S    6  0:00 xclock -d
   100  1001  1051  1050  14   0   2080  1400 wait4       S   p0  0:00 -bash 
100000  1001  1074  1051  17   0   1068   528             R   p0  0:00 ps axl 

Para dar una idea de la situación de parentescos entre los distintos procesos mostramos la salida obtenida con el comando 'pstree' ejecutado desde la misma sesión de xterm que en el caso anterior.

$ pstree -p > pstree-p.out ; cat pstree-p.out
init(1)-+-apache(262)-+-apache(274)
        |             |-apache(275)
        |             |-apache(276)
        |             |-apache(277)
        |             `-apache(278)
        |-atd(254)
        |-bash(268)
        |-bash(270)---vi(916)
        |-bash(273)---xinit(1029)-+-XF86_S3V(1034)
        |                         `-mwm(1037)-+-.xinitrc(1042)---xterm(1050)---bash(1051)---pstree(1068)
        |                                     `-.xinitrc(1045)---xclock(1058)
        |-cron(257)
        |-getty(269)
        |-getty(271)
        |-getty(272)
        |-gpm(200)
        |-inetd(195)
        |-kflushd(2)
        |-klogd(188)
        |-kpiod(4)
        |-kswapd(5)
        |-kupdate(3)
        |-lpd(210)
        |-portmap(193)
        |-postmaster(226)
        |-sendmail(237)
        |-sshd(241)
        |-syslogd(186)
        `-xfs(244)

Solo vamos a procesar los campos PID y PPID. $3 y $4 respectivamente. Los meteremos en un par de arrays llamados pid y ppid.

BEGIN { ind=0;  }

function padre(p){
   for (i=0; i", proc);
      proc= padre(proc);
  } while ( proc >= 1 )
  printf ("\n\n");
}

Ahora ejecutamos pasando el pid del proceso del cual deseamos averiguar su descendencia.

$ awk -f ancestros.awk proc=1051 < ps-axl.out

1051->1050->1042->1037->1029->273->1->

Con un número realmente reducido de líneas de código acabamos de procesar la salida de un comando que no estaba especialmente diseñado para ser procesado sino para entregar un resultado legible.

No se emocione todavía porque solo hemos utilizado los arrays con indices numéricos. Lo cierto es que los arrays de 'awk' a diferencia de los arrays de otros lenguajes son arrays asociativos. Eso significa que podemos usar como índice una cadena de caracteres. Por ejemplo podemos hacer lo siguiente: nombre_cli["5143287H"]="Luis, García Toledano"

No es necesario dar un tamaño al array. Un array asociativo no establece un orden entre sus elementos. Hay que aclarar que el manejo de un array con índices numéricos corresponde a un mecanismo muy simple ya que se usan porciones consecutivas de memoria del ordenador y se accede directamente por posición. Por el contrario un array asociativo de las características de 'awk' se va creando dinámicamente. Internamente 'awk' gestiona el acceso mediante una técnica de hash que usa tablas auxiliares a modo de tablas de índices y funciones auxiliares que obtiene valores numéricos a partir de valores de una cadena. Todo ello permite un acceso muy rápido en este tipo de estructuras haciéndolas adecuadas para su uso en bases de datos.

FTLSUSE |CURSOS  |FTLinuxCourse para SuSE                                | 11800
FTLREDH |CURSOS  |FTLinuxCourse para RedHat                              | 11800
ASUSCOM |HARDWARE|Asuscom ISDNLink 128k Adapter (PCI)                    |  6865
RAILROAD|JUEGOCOM|Railroad Tycoon (Gold Edition)                         |  7700
CIVILIZ |JUEGOCOM|Civilization: Call to power                            |  7700
MYTHII  |JUEGOCOM|Myth II                                                |  7700
LIAPPDEV|LIBROS  |Linux Application Development (537 Páginas)            | 11000
CONECT01|LIBROS  |Guía del Usuario de Linux  (413 Páginas)               |  5300
CONECT03|LIBROS  |Guía del Servidor (Conectiva Linux 437 Páginas)        |  5300
CONECT02|LIBROS  |Guía del Administrador de redes (465 Páginas)          |  5300
LIUSRESU|LIBROS  |Linux User's Resource (795 Páginas)                    | 12000
RH70DLUX|LINUXCOM|RedHat Linux 7.0 Deluxe en español                     |  9600
RH70PROF|LINUXCOM|RedHat Linux 7.0 Profesional en Español                | 20000
SUSE70  |LINUXCOM|Suse Linux 7.0 (6CDs)(Version española)                |  6850
RTIME22 |LINUXCOM|RealTime 2.2 (1CD)                                     | 13000
CONCT50E|LINUXCOM|Conectiva Linux 5.0 Versión Económica Español (6CDs)   |  5200
CITIUS22|LINUXCOM|Linux Citius 2.2                                       |  7750
TRBLIW60|LINUXCOM|Turbolinux Workstation 6.0                             |  6500
MOTIF   |LINUXCOM|Motif Complete                                         | 22000
CONCTSRV|LINUXCOM|Conectiva Linux  Ed.Servidor (Español 3CDs + 4 Manua   | 27500
RHORA8I |LINUXCOM|RedHat Linux Enterprise Edition optimized for Oracle8i |270000
MANDRA72|LINUXCOM|Mandrake 7.2  (7CDs) PowerPack Deluxe (versión española|  8300
PINGUINO|SUSEPROM|Pingüino de peluche                                    |  6000

BEGIN { 
   FS="[\ \t]*\|[\ \t]*" ;
   while ( getline < "articulos.dat" > 0) {
     artic[$1]= "(" $4 " Ptas + Iva) " $3;
     printf ("%s ", $1);
   }
   for (;;){
      printf ("\n\nIntroduzca un código de artículo o solo  para terminar: ");
      getline codigo ;
      if (codigo == "" )
         break;
      printf ("\n<%s>\n%s", codigo, artic[codigo]);	 
  }
}

$ awk -f articulos.awk

FTLSUSE FTLREDH ASUSCOM RAILROAD CIVILIZ MYTHII LIAPPDEV CONECT01 CONECT03 
CONECT02 LIUSRESU RH70DLUX RH70PROF SUSE70 RTIME22 CONCT50E CITIUS22 TRBLIW60 
MOTIF CONCTSRV RHORA8I MANDRA72 PINGUINO

Introduzca un código de artículo o solo  para terminar: RH70PROF


(20000 Ptas + Iva) RedHat Linux 7.0 Profesional en Español

Introduzca un código de artículo o solo  para terminar: CITIUS22


(7750 Ptas + Iva) Linux Citius 2.2

Introduzca un código de artículo o solo  para terminar:
$

El programa que acabamos de realizar ilustra la potencia de 'awk' para el tratamiento de ficheros de datos. Si nuestro fichero de datos de ejemplo 'articulos.dat' tuviera un número de registros mucho mayor habríamos notado que inicialmente se tarda un cierto tiempo en leer todo el fichero de datos pero una vez almacenados los datos en el array su acceso a los mismos es rapidísimo. Esta rápidez se debe no solo a que los datos ya han sido leidos desde el disco duro y ya están en memoria sino porque toda la información está indexada de forma que la localizacion de cualquier elemento del array es muy rápida.

Faltan muchas cosas por contar sobre 'awk'. Si dispone de algún fichero de datos de interes personal saque una copia e intente realizar alguna utilidad en 'awk'.

Si quiere hacernos llegar alguna duda, aclaración,
crítica, o contribución personal, utilice nuestro
formulario de contacto y nosotros le contestaremos
contacto