Awk
awk es un lenguaje de analisis y procesado orientado a patrones de texto. Esta disenado para hacer sencilla las tareas de recopilacion comun de informacion y manipulacion de texto.
En la practica, el uso de awk suele caer en dos amplias categorias. Una es la que podria considerarse generacion de informes: esto implica el procesado de una entrada para extraer conteos, sumas, subtotales, etcetera. Esto tambien incluye la escritura de programas de validacion de datos triviales, como la verificacion de campos que contengan contiene unicamente informacion numerica o analizar si ciertos delimitadores estan adecuadamente balanceados.
Una segunda categoria es su uso como transformador de datos, convirtiendo datos de la forma producida por un programa en la esperada por otro distinto. Los ejemplos mas simples consisten en simplemente seleccionar campos, y tal vez reorganizarlos.
awk resulta invaluable para el el procesado textual y numerico combinado. Fue creado por Aho, Weinberger y Kerningham en los Laboratorios Bell, de alli su nombre.
Uso basico
La operacion basica de awk es analizar un conjunto de lineas de entrada en orden buscando por coincidencias que se han especificado. Para cada patron, puede especificarse una accion; esta accion sera llevada a cabo en cada linea que muestre coincidencias, y se le dara salida (mostrandolo en la terminal o redirigiendola).
El comando
awk programa [ficheros]
ejecuta los comandos de awk de la cadena programa
sobre
el conjunto de ficheros
especificados, o bien utilizara la
entrada estandar si no se hubiesen espeficado fichero alguno para
analizar. La declaracion tambien puede volcarse a un
fichero_salida
con el prefijo -f
:
awk -f fichero_salida [ficheros]
Estructura de Programa de awk
Un programa de awk es una secuencia de declaraciones que guardan la siguiente sintaxis:
patron { accion }
A su turno, cada linea de entrada resulta analizada por awk contra cada patron. En cada uno de los patrones en los que encuentre coincidencia, awk ejecutara la accion solicitada. Una vez que awk ha finalizado de evaluar todos los patrones solicitados en la linea, cargara la siguiente linea, y comenzara nuevamente el analisis de la misma.
Como en las declaraciones del programa awk tanto los patrones como
acciones son opcionales, como forma de distinguir unos de otras se
encierra la accion entre llaves {}
para distinguirla.
En cada declaracion del programa pueden omitirse tanto el patron como accion, pero no pueden omitirse ambas:
- Si la accion carece de patron, la accion se ejecutara para todas las lineas de entrada.
- Si un patron carece de accion, la linea coincidente se devolvera como salida (una linea con muchos patrones coincidentes sera impresa varias veces).
Naturalmente, las lineas cuyos patrones no resultan en coincidencia, son ignoradas ("filtradas").
Pueden disponerse comentarios en los programas de awk (los cuales
tambien resultan filtrados). Estos comienzan con el caracter
#
y finalizan con el final de la linea, como en
patron { accion } # Este es el comentario de la linea.
Registros y Campos
La entrada de awk se divide en registros finalizados
por un separador de registro. El separador de registro por
defecto es un caracter ASCII nulo de nueva linea. En cristiano, esto
significa que de modo que por defecto, awk procesa la entrada de a una
linea por vez. El numero del registro actual se dispone en una variable
denominada NR
.
Cada registro se considera dividido en campos. Los
campos normalmente estan separados por un caracter de espacio
(en blanco o de tabulacion). Pero el separador de campo de
entrada es asingable. Los campos se refieren como $1
,
$2
, etcetera, siendo $1
el primer campo,
$2
el segundo, etc, y donde $0
representa todo
el registro de entrada.
Los campos pueden ser asignados. El numero de campos en el registro
actual forma parte de la variable denominada NF
.
Las variables FS
y RS
refieren al
separador de campo y separador de registro. Estos
pueden ser asignadas en cualquier momento por un unico caracter. Por
ejemplo, para asignar el caracter c
como separador de campo
en la variable FS
, se utiliza el argumento opcional de
linea de comandos -Fc
.
En caso que el separador de registro este vacio, se considera como
separador de registro por defecto a una linea vacia, y los
separadores de campo por defecto son los caracteres en
blanco (tabulacion
y nuevas linea
) se
consideran como.
La variable FILENAME
se utiliza para contener el nombre
del fichero de entrada actual.
Patrones
Un patron en frente de una accion opera como un semaforo que determina si la accion debe ejecutarse.
Como patron podran utilizarse una variedad de expresiones de control: expresiones regulares, expresiones relacionales aritmeticas, expresiones de cadena, y combinaciones booleanas arbitrarias.
La accion mas simple consiste imprimir algo o todo de de un registro;
esto se realiza con el comando print
de awk.
El siguiente comando imprime todas los registros, copiando la entrada a la salida de forma intacta.
{ print }
Resulta mas util imprimir un campo o campos de cada registro, por ejemplo, imprimir los primeros dos campos en orden inverso:
print $2, $1
Los items separados por ,
en la declaracion de impresion
resultaran separados por el separador de campo de salida actual, cuando
se les de salida. Los items que no esten separados por comas en la
entrada, resultaran concatenados. De este modo, para correr el primer y
segundo campos juntos, se utiliza:
print $1 $2
Se pueden utilizar las variantes predefinidas NF
y
NR
, por ejemplo, para imprimir cada registro precedida por
el numero de registro y el numero de campo.
{ print NR, NF, $0 }
La salida puede dividiise en multiples ficheros, por ejemplo el
programa siguiente escribe el primer campo $1
en
fichero1
y el segundo campo en el
fichero2
.
{ print $1 >"fichero1"; print $2 >"fichero2" }
Tambien puede usarse la notacion >>
para
agregar la salida al fichero1
(se lo creara de ser
necesario).
print $1 >>"fichero1"
El nombre de fichero puede ser una variable o un campo, asi como una constante. Por ejemplo, para usar los contenidos del campo 2 en el nombre:
print $1 >$2
De forma similar, la salida puede entubarse a otro proceso, por ejemplo:
print | "mail bwk"
envia por correo electronico la salida a bwk.
Las variables OFS
y ORS
pueden utilizarse
para cambiar el separador de campo de salida y el separador de registro
de salida. El separador de registro de salida se agrega a la salida de
la declaracion print
.
Awk tambien provee a la declaracion printf para formateado de salida, con esta sintaxis:
printf expresion, expresion, ....
Por ejemplo, para imprimir $1
como una cifra de coma
flotante de 8 cifras, con dos luego de la coma, y $2
como
una cifra decimal de 10 digitos, seguida por una nueva linea, se
usaria:
printf "%8.2f %10ld\nm $1, $2
Un ejemplo de un programa awk que imprime la tercera y segunda columna de una tabla en dicho orden:
[print $3; $2]
Este imprime todas las lineas de entradas con una A
,
B
, o C
en el segundo campo:
$2 ~/A|B|C/]
Este imprime todas las lineas en las cuales el primer campo es diferente que el primer campo previo:
$2 ~/A|B|C/]
BEGIN y END
El patron especial BEGIN
coincide con el comienzo de la
entrada, antes de que sea leido el primer registro. El patron
END
coincide con el final de la entrada, despues de que el
registro ha sido procesado. Por lo tanto, BEGIN
y
END
proveen una forma de inicializacion o obtencion de
control previo, y luego de procesar, como indicativo de cedido de
control final.
Por ejemplo, el separador de campo puede configurarse en un
;
con:
BEGIN { FS = ";" }
...resto del programa...
...O las lineas de entrada pueden contarse con
END { print NR }
Naturalmente, si BEGIN
esta presente en el primer
patron, END
debe aparecer en el ultimo utilizado.
Expresiones regulares de awk
La expresion regular mas simple es la cadena literal de caracteres,
cerrada entre barras /
, como /perez/
Esto representa realmente un programa completo de awk que imprimira
todas las lineas que contienen cualquier ocurrencia del nombre
perez
. Si una linea contiene perez
como parte
de una palabra mas grande, tambien resultara coincidente, como
perezoso
.
Las expresiones regulares de awk incluyen las formas de expresiones
regulares encontradas en el editor ed y grep. Adicionalmente, awk permite agrupar con
()
, alternar con |
, "una o mas" con
+
, y ?
para "cero o uno", todas como en
lex
. Las clases de caracteres pueden abreviarse:
[a–zA–Z0–9]
es el conjunto que solicita todas las letras y
digitos..
Por ejemplo, este programa de awk:
/[Aa]bad |[Ww]enceslao |[Kk]arina/
...imprimira todas las lineas que contengan cualquiera de los nombres ‘‘Abad,’’ ‘‘Wenceslao’’ o ‘‘Karina,’’ esten en mayusculas o no.
Las expresiones regulares de awk deben encerrarse en barras
//
, al igual que en ed y sed. Los espacios en blanco u los metacaracteres
de expresiones regulares dentro de las expresiones regulares son
importantes. Para impedir el interpretado de estos metacaracteres,
precedalos con una barra invertida \
.
Por ejemplo, este patron busca coincidencias de cualquier cadena de
caracteres entrecerrados en las barras: / \/ .∗\//
Tambien podra especificar que cualquier campo o variable busque
coincidencia de una expresion regular (o no coincida con ella, utilizano
los operadores ∼
y !∼
.
Por ejemplo, este programa de awk imprime todas las lineas donde el
primer campo coincide con juan
o Juan
. Note
que esto tambien coincidira con Juana
,
San Juan
, etcetera.
$1 ∼ /[jJ]uan/
Para restringir la coincidencia a exactamente [jJ]uan
,
debe usarse:
$1 ∼ /ˆ[jJ]uan$/
El circunflejo ˆ
refiere al comienzo de la linea o
campo, mientras que el signo pesos $
refderira al final de
linea o campo.
Expresiones Relacionales de awk
Los patrones de awk pueden ser expresiones relacionales que incluyan
los operadores
relacionales convencionales <
, <=
,
==
, !=
, >=
, y
>
. Un ejemplo es $2 > $1 + 100
que
seleccionara las lineas donde el segundo campo es al menos un
100
mayor que el primer campo. De forma similar,
NF % 2 == 0
...imprime las lineas con el un numero de campos par.
Sin embargo, si ninguno de los operandos sometidos a evaluacion relacionar fuese numerico, se realizara una comparacion de cadenas de caracteres alfabeticos.
Por lo tanto este programa selecciona las lineas que comienzan con
una s
, t
, u
, etc.
$1 >= "s"
En la ausencia de cualquier otra informacion que permita dilucidar el contexto, se asumen los campos como cadenas alfabeticas. De esta forma, este programa realizara una comparacion de cadena alfabetica:
$1 > $2
Patrones Combinacionales
Un patron puede ser cualquier operador combinacinoal de
logica booleana OR ||
, AND &&
, y
NOT !
.
Por ejemplo, este programa de awk selecciona las lineas donde un
primer campo comienza con p
, pero no sea
perez
. El &&
y el ||
garantizan que sus operandos sean evaluados de izquierda a derecha; la
evaluacion se detendra tan pronto como se verifique verdad o
falsedad.
$1 >= "p" && $1 < "q" && $1 != "perez"
Rangos de Patrones
El patron
que selecciona una accion puede consistir de
dos patrones separados por ,
, siguiendo la sintaxis
patron1, patron2 { ... }
En este caso, la accion se realiza para cada linea entre una
ocurrencia de patron1
y la siguiente ocurrencia de
patron2
(inclusive). Por ejemplo, /empezar/
,
/detener/
imprime todas las lineas existentes entre las
cadenas empezar
y denener
, mientras que
NR == 100, NR == 200 { ... }
realiza la accion desde la
linea 100
hasta la linea 200
de la
entrada.
Acciones
Una accion de awk consiste en una secuencia de declaraciones
de accion finalizadas por un caracter nulo de nueva linea o bien un
;
.
Dichas declaraciones de accion pueden utilizarse para realizar una variedad de tareas de manipulacion de cadenas o de registro.
Las declaraciones pueden ser una de las siguientes:
- Declaracion
if (expresion) [declaracion else]
- Declaracion
while (expresion)
- Declaracion
for (expreion; expresion; expresion)
- Declaracion
for (var en array)
- Declaracion
do
while (expresion)
break
continue
{ [declaracion ...] }
expression
(conmunmentevar = expression
print [expresion-lista] [>expression]
printf format [..., expresion-lista] [>expresion]
return [expresion]
next
(saltea los patroners remanentes de esta linea de entrada)nextfile
(saltea lo siguiente en este fichero, abre el siguiente, comienza desde arriba)delete array[expression]
(borra un elemento del array)delete array
(borra todos los elementos del array)exit [expresion]
(sale del procesado y realiza procesadoEND
; el status seraexpresion
)
Funciones Incorporadas
Awk incorpora la funcion lenght
para computar la
longitud de una cadena de caracteres. Este programa imprimira cada
registro, precedido por su longitud:
{print length, $0}
Por si misma, length
es una pseudo-variable que
abarca la longitud del registro actual; length(argumento)
es una funcion que almacena la longitud de su argumento. En este
rpgorama, el argumento puede ser cualquier expresion:
{print length($0), $0}
Awk tambien incorpora las funciones aritmeticas raiz cuadrada
sqrt
, logaritmo log
, exponencial
exp
, e integral int
, como parte de sus
respectivos argumentos.
El nombre de dichas funciones incorporadas, sin argumento o entre parentesis, significaran un valor de funcion para el registro entero.
Este programa imprime lineas cuya longitud sea inferior a 10 o mayor que 20:
length < 10 || length > 20
La funcion incorporada substr(c, m, n)
produce la
subcadena c
que comienza en una posicion m
(origen 1) y tiene como maximo n
caracteres de longitud. Si
se omite n
, la subcadena va hasta el final de la subcadena
c
.
La funcion incorporada index(c1, c2)
devuelve el indice
binario donde la cadena c2
ocurre en c1
,
resultando 0
si no lo hace.
La funcion sprintf(f, e1, e2, ...)
produce el valor de
las expresiones e1
, e2
, etc., en el forma
printf fespecificado por f
.
Por ello, en el ejemplo,
x = sprintf("%8.2f %10ld", $1, $2)
...pondra la x
a una cadena producida por el formateo de
los valores de $1
y $2
.
Variables, Expresiones, y Asignaciones
Las variables de awk toman valores numericos (coma flotante) o
cadenas alfabeticas de acuerdo al contexto. Por ejemplo, en
x = 1
, x
es claramente una cifra, mientras que
en x = "perez"
es claramente una cadena alfanumerica. Las
cadenas se convierten a numeros y viceversa, toda vez que el contexto lo
demande. Por ejemplo:
x = "3" + "4"
...asigna 7
a la x
.
Las cadenas que no pueden ser interpretadas numericamente en un
contexto numerico generalmente tienen un valor numerico de
0
, pero no suele ser adecuado contar siguiendo este
comportamiento.
Por defecto las demas variables que no son las incorporadas, deben
inicializarse a una cadena nula, que tiene un valor numerico de
0
; esto elimina la necesidad de la mayoria de las secciones
de tipo BEGIN
. Por ejemplo, la sima de los primeros dos
campos puede computarse con:
{ s1 += $1; s2 += $2 }
END { print s1, s2 }
La aritmetica se hace internamente en coma flotante. Los operadores
arimeticos son +
, –
, ∗
,
/
, y %
(porcentaje o modulo).
Tambien estan disponibles los operadores de C para incremento
++
y decremento ––
, asi como los operadores de
asignacion +=
, –=
, ∗=
,
/=
, y %=
. Estos operadores pueden utilizarse
en las expresiones.
Variables de Campo
Los campos en awk comparten esencialmente todas las propiedades de las variables: pueden usarse en aritmetica u operaciones de cadenas, y tambien pueden ser asignados. Por lo tanto puede reemplazarse el primer campo con un numero de secuencia:
{ $1 = NR; print }
...o bien acumular dos campos en un tercero, asi:
{ $1 = $2 + $3; print $0 }
...o incluso asignar una cadena a un campo:
{ if ($3 > 1000)
$3 = "demasiado grande"
print
}
...lo cual reemplaza el tercer campo con
"demasiado grande"
cuando lo es, y en cualquier caso
imprime el registro.
Pueden usarse expresiones numericas para referenciar campos:
{ print $i, $(i+1), $(i+n) }
...donde la consideracion de campo como numerico o cadena depende del
contexto; en casos ambiguos como if ($1 == $2) ...
los
campos son tratados como cadenas.
Cada linea de entrada se divide en campos automaticamente de ser necesario. Tambien es posible dividir cualquier variable o cadena en campos:
n = split(c, arreglo, sep)
...divide la cadena c
en un arreglo[1], ..., arreglo[n].
El numero de elementros encontrados resulta devuelto. Si se provee el
argumento sep
, se utiliza como separador de campo; de otra
forma se usa como separador FS
.
Concatenacion de cadenas
Las cadenas pueden concatenarse. Por ejemplo:
length($1 $2 $3)
...revuelve la longitud de los primeros tres campos. O en una declaracion impresa:
print $1 " es " $2
...imprime los dos campos separados por " es "
. Las
variables y expresiones numericas tambien pueden aparecer en las
concatenaciones.
Arreglos de awk
Los elementos de los arreglos de awk no necesitan ser declarados; activan su existencia simplemente por ser mencionados. Los subscriptos pueden tener cualquier valor no nulo, incluyendo cadenas no numericas. Como ejemplo de un subscripto convencional, la declaracion
x[NR] = $0
asigna el registro de entrada actual al elemento nro. NR
del arreglo x
. De hecho, es posible procesar toda la
entrada entera en orden aleatorio con el siguiente programa de awk:
{ x[NR] = $0 }
END { ... programa ... }
La primer accion meramente registra cada linea de entrada en el
arreglo x
.
Los elementos del arreglo pueden ser nombrados por valores no
numericos. Supongamos que la entrada contiene campos con valores como
manzana
, naranja
, etc. Este programa
incrementara el contador de los elementos del arreglo nombrado, y los
imprime al final de la salida:
/manzana/
/naranja/
END
{ x["manzana"]++ }
{ x["naranja"]++ }
{ print x["manzana"], x["naranja"] }
Declaraciones de control de flujo
Como en el lenguaje C, Awk ofrece las declaraciones basicas de
control de flujo if-else
, while
,
for
, y el agrupado de declaraciones con llaves
{}
.
Primero se evalua la condicion entre parentesis ()
; si
es verdadera, se ejecuta la declaracion siguiente a if
. La
seccion else
es opcional.
La declaracion while
procede como en C. Para imrpirmir
todos los campos de entrada uno por linea:
i = 1
while (i <= NF) {
print $i
++i
}
La declaracion for
opera como en C:
for (i = 1; i <= NF; i++)
print $i
...hace lo mismo que la declaracion while
explicada.
Existe una forma alternativa para la declaracion for
que se
adecua para acceder a los elementos de un arreglo asociativo:
for (i in array)
statement
...donde la declaracion i
activa cada elemento del
arreglo. Los elementos son accedidos en un orden aparentemente
aleatorio. Surgira el caos is se altera el i
, o si
cualquier elemento nuevo se accede durante el bucle.
La expresion en la seccion de la condicion de un if
,
while
or for
puede incluir operadores
relacionales como <
, <=
,
>
, >=
, ==
("igual a"), y
!=
("no igual a"); coincidencias de expresiones regulares
con operadores de coincidencia ∼
y !∼
; los
operadores logicos ||
, &&
, y
!
; y por supuesto las parentesis ()
para
agruparlos.
La declaracion break
provoca la salida inmediata de un
while
o for
encerrado; la declaracion
continue
provoca el cimienzo de la siguiente iteracion.
La declaracion next
provoca que awk saltee
inmediatamente al segundo registro y cominece a analizar los patrones
desde el inicio. La declaracion exit
provoca que el
programa se comporte como si hubiese ocurrido la finalizacion de la
entrada.