Introdução
O AWK é uma linguagem utilizada em ambientes UNIX para processar dados baseados em texto. Na edição anterior apresentámos aqui um artigo de introdução a esta linguagem. Nesta edição, apresentamos alguns dos seus aspectos mais avançados.
Campos e variáveis
Nos exemplos anteriores, os acessos a campos eram sempre feitos através de um literal inteiro (do tipo $1
). No entanto, este acesso também pode ser feito através de um inteiro armazenado numa variável.
Por exemplo, o seguinte programa lê um número no primeiro campo e escreve o seu conteúdo:
{ campo = $1; print $campo }
Para além disto, os campos (tal como as variáveis especiais) podem ser modificados como se fossem variáveis. Por exemplo, o seguinte programa escreve o input sem o segundo campo:
{ $2 = ""; print }
Arrays
Em AWK é possível definir arrays (apenas unidimensionais) para guardar um conjunto de valores relacionados. Apesar de apresentarem uma sintaxe semelhante aos arrays utilizados em C, existem algumas diferenças quanto à sua forma de utilização:
- Não é necessário especificar uma dimensão para o array. Ele é ajustado automaticamente sempre que é necessário guardar um novo valor;
- Os arrays são associativos, ou seja, funcionam como um mapa entre uma chave (o índice) e um valor.
O seguinte exemplo ilustra as vantagens da utilização deste tipo de arrays, contando as palavras (registos) no input:
{ for(i = 1; i <= NF; i++) contador[$i]++ } # O ciclo é executado para cada linha de input. END { for(palavra in contador) print palavra, contador[palavra] }
A sintaxe do ciclo for na última linha permite iterar sobre todos os elementos de um array.
Este ciclo for
no final corresponde à iteração sobre o array. Note-se que este ciclo não garante a ordem no acesso às posições do array. Note-se que este ciclo não garante a nenhuma ordem no acesso aos dados.
A instrução delete
pode ser utilizada para remover um elemento do array.
Funções
As funções tem como objectivo simplificar a resolução de problemas que de outra forma se tornariam complexos. Como há funções às quais é necessário recorrer com alguma frequência, existem um conjunto de funções predefinidas e prontos a ser utilizadas.
Funções sobre números
sqrt(n)
: Devolve a raíz quadrada den
;log(n)
: Devolve o logaritmo de base e den
;exp(n)
: Devolve a potência de base e den
;int(n)
: Devolve a parte inteira den
.
Exemplos:
sqrt(4) # Devolve 2 sqrt(5) # Devolve 2,23607 log(1) # Devolve 0 log(2) # Devolve 0,693147 exp(0) # Devolve 1 exp(1) # Devolve 2,71828 int(3.14159) # Devolve 3
Funções sobre strings
substr(string, inicio, tamanho)
: Devolve a substring destring
que começa eminicio
e tem o tamanhotamanho
.split(string, array, separador)
: Guarda emarray
as substrings destring
separadas pela stringseparador
. É usado um espaço como separador se este for omitido.index(string, padrao)
: Devolve o índice da primeira ocorrência depadrao
emstring
(ou 0 se não existir nenhuma ocorrência).
Nota: O ínicio da string corresponde ao índice 1. Da mesma forma, a função split coloca as substrings em índices a partir de 1.
Exemplos:
substr("programar", 4, 4) # Devolve "gram" split("portugal-a-programar", palavras, "-") print palavras[1] # portugal print palavras[2] # a print palavras[3] # programar index("portugal-a-programar", "port") # Devolve 1 index("portugal-a-programar", "b") # Devolve 0
”printf” e ”sprintf”
Tem sido usada a instrução print
para escrever texto no ecrã. No entanto, também é possível usar a função printf
para produzir uma string formatada.
A formatação através da função printf
funciona da mesma forma que em C, utilizando (principalmente) os seguintes códigos de controlo de formato:
%c
: Escreve um char;%d
: Escreve um int em formato decimal;%f
: Escreve um float;%o
: Escreve um número em formato octal;%s
: Escreve uma string;%u
: Escreve um unsigned int;%x
: Escreve um int em formato hexadecimal.
Com isto, é possível escrever o número de cada registo do input em formatos decimal e hexadecimal com o seguinte programa:
{ printf("%d %x\n", NR, NR) }
Será produzido o seguinte texto:
1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 a 11 b 12 c 13 d 14 e 15 f 16 10 17 11 18 12 19 13 20 14
A função sprintf
funciona de forma análoga, mas devolve a string em vez de a escrever.
Funções definidas pelo utilizador
Para além das funções predefinidas, é possível também definir novas funções. Estas funções devem ser definidas no início do programa (antes do primeiro bloco). Para o fazer utiliza-se a seguinte sintaxe:
function nome(parametros) { instrucoes }
A instrução return
indica qual o valor a ser devolvido pela função quando a sua execução termina.
Redireccionamento de output
Para além de escrever o resultado no ecrã, também é possível enviá-lo para um ficheiro ou comando. Em AWK existem três operadores relacionados com o redireccionamento de output:
>
: Redirecciona o output para um ficheiro;>>
: O mesmo que o anterior, mas caso o ficheiro já exista o output é adicionado no fim;|
: Redirecciona o output para um comando Unix.
Por exemplo, é possível enviar o número de cada registo para um ficheiro out.txt
com o seguinte programa:
{ print NR >> "out.txt" }
Conclusão
Este artigo serve de complemente ao artigo introdutório publicado na edição anterior. Este artigo pode parecer complexo para um programador não-familiarizado nesta linguagem, sendo nesse caso aconselhável a leitura do referido artigo na edição anterior.