Introdução ao Awk
O Awk tem suas origens em sed e grep, que por sua vez derivam do ed, o editor de linha original do Unix. Veremos que Awk e sed compartilham muitas semelhanças.
O que é Awk?
Awk foi projetado para processamento de texto e é geralmente usado como uma linguagem interpretada para extração de dados e ferramentas de relatório.
Awk fornece um modelo computcaional mais geral para processamento de arquivos.
Programas em Awk diferem da maioria das outras linguagens: programas em Awk são orientados a dados, descrevendo os dados que você deseja processar e o que fazer quando encontrá-los; a maioria das outras linguagens é procedural, exigindo uma descrição detalhada de cada passo que o programa deve executar.
Um exemplo típico de programa em Awk é converter dados em relatórios formatados.
Outro exemplo é um aplicativo de processamento de dados composto por itens de dados independentes e programas de recuperação de dados: os itens de dados são registros estruturados; a recuperação de dados é o processo de extrair dados de arquivos e formar relatórios.
A chave para todas essas operações é que os dados possuem alguma estrutura, ou seja, os precisam ser classificados de alguma forma.
Awk não pode processar arquivos não textuais, como arquivos binários executáveis (seria necessário usar um editor binário como o hexlmode do emacs).
Similar ao sed, a função básica do Awk é pesquisar linhas em arquivos que contenham certos padrões (ou outras unidades de texto). Quando uma linha corresponde a um padrão, o Awk executa uma ação especificada naquela linha. O Awk continua processando as linhas de entrada dessa maneira até o final do arquivo.
Sintaxe Básica do Awk
Um programa em Awk consiste em uma série de instruções Awk. Uma instrução Awk é composta por um padrão (pattern) seguido por uma ação (action). A ação está entre chaves {} para separá-la do padrão. As instruções Awk são geralmente separadas por caracteres de nova linha.
Sintaxe: pattern {action}
Existem duas maneiras de executar o Awk:
- Quando o programa Awk é curto: awk [OPÇÕES] [--] texto-do-programa arquivo ...
- Quando o programa Awk é longo, é mais conveniente colocá-lo em um arquivo: awk [OPÇÃO] -f arquivo-do-programa [--] arquivo ...
Pode-se ver que um comando Awk consiste em opções, um arquivo de programa ou instruções Awk, e nomes de arquivos de entrada. Se nenhum nome de arquivo de entrada for especificado ou se for especificado como -, a entrada é obtida da entrada padrão.
As opções comuns são:
| Opção | Uso | Descrição |
|---|---|---|
| -F | -F fs | Especifica o separador de colunas fs para os dados de entrada |
| -v | -v var=valor | Antes da execução do programa Awk, atribui um valor à variável var. Esses valores são usados no bloco BEGIN do programa Awk. |
| -f | -f arquivo-do-programa | Especifica um arquivo de programa Awk, em vez de especificar instruções Awk na linha de comando. |
| -- | -- | De acordo com as convenções de análise de parâmetros POSIX, esta opção representa o final das opções da linha de comando. Por exemplo, usando esta opção, é possível especificar arquivos de entrada que começam com "-", caso contrário, eles seriam interpretados como opções da linha de comando. |
Priemiro Comando Awk
# O Awk executará seu comando print em cada linha do arquivo dados.txt
# Quando o comando print não tem parâmetros, ele imprime todo o conteúdo da linha atual
$ awk '{ print }' dados.txt
Sistemas - Linux
Banco de Dados - PostgreSQL, MongoDB etc.
Segurança - Firewall, Rede, Segurança Online etc.
Desenvolvimento - Aplicativos Web
# Comando print com a variável $0, que representa a linha inteira
$ awk '{ print $0 }' dados.txt
Sistemas - Linux
Banco de Dados - PostgreSQL, MongoDB etc.
Segurança - Firewall, Rede, Segurança Online etc.
Desenvolvimento - Aplicativos Web
# Comando print com string fixa, então para cada linha no arquivo de entrada, a string fixa é impressa
$ awk '{ print "ola" }' dados.txt
ola
ola
ola
ola
Usando Awk para Imprimir Colunas Específicas
# Sem especificar um separador de colunas, o Awk usa por padrão o espaço em branco como separador
$ awk '{ print $1 }' dados.txt
Sistemas
Banco de Dados
Segurança
Desenvolvimento
# Usando a opção -F para especificar o caractere | como separador de colunas
$ awk -F'|' '{ print $2 }' dados.txt
Linux
PostgreSQL, MongoDB etc.
Firewall, Rede, Segurança Online etc.
Aplicativos Web
Lendo Instruções Awk de um Arquivo de Programa
$ cat segundaColuna.awk
BEGIN {
FS="|"
}
{ print $2 }
# Usando a opção -f para especificar o arquivo de programa Awk
$ awk -f segundaColuna.awk dados.txt
Linux
PostgreSQL, MongoDB etc.
Firewall, Rede, Segurança Online etc.
Aplicativos Web
Blocos BEGIN e END no Awk
Normalmente, o Awk executa o código do programa uma vez para cada linha de entrada. Para quando você precisa executar algum código de inicialização antes que o Awk comece a processar o texto no arquivo de entrada, você pode definir um bloco BEGIN, usado para inicializar variáveis como a variável FS (separador de colunas), imprimir cabeçalhos ou inicializar outras variáveis globais.
Usando Expressões Regulares no Awk
O Awk pode usar expressões regulares para executar seletivamente um bloco de código independente, mas a expressão regular deve estar entre barras, semelhante ao sed, ou usar o operador /! para especificar se qualquer coluna ou variável corresponde/não corresponde a uma expressão regular.
# Linhas que contêm a string "Linux"
$ awk '/Linux/{ print }' dados.txt
Sistemas - Linux
$ awk -F'|'/Linux/{ print $1 }' dados.txt
Sistemas
# Segunda coluna que corresponde a "MongoDB"
$ awk '$2 ~ /MongoDB/ { print $1 }' dados.txt
Banco de Dados
Expressões e Blocos no Awk
O método do Awk para executar seletivamente blocos de código: colocar qualquer tipo de expressão booleana antes do bloco para controlar quando um bloco específico pode ser executado, ou seja, apenas quando o valor da expressão booleana antes do bloco for verdadeiro, o Awk executará esse bloco.
# Terceira coluna de todas as linhas em /etc/passwd onde a primeira coluna é igual a "root"
$ awk 'BEGIN { FS=":" } $1 == "root" { print $3 }' /etc/passwd
0
Sintaxe: variável operador expressão regular ou string
Operadores de comparação: ==, <, >, <=, >=, !=
Além disso: ~ (corresponde), !~ (não corresponde)
$ cat dados.txt
Sistemas - Linux
Banco de Dados - PostgreSQL, MongoDB etc.
Segurança - Firewall, Rede, Segurança Online etc.
Desenvolvimento - Aplicativos Web
# Primeira coluna de linhas onde a segunda coluna (separada por |) corresponde à string "Web"
$ awk 'BEGIN { FS="|" } $2 ~ "Web" { print $1 }' dados.txt
Desenvolvimento
As expressões são componentes fundamentais dos programas Awk. Uma expressão pode avaliar o conteúdo que você imprime, testa ou passa para uma função, ou pode usar operadores de atribuição para atribuir um novo valor a uma variável ou a uma coluna.
A maioria dos outros tipos de instruções contém uma ou mais expressões que especificam onde os dados são processados. Como em outras linguagens, as expressões do Awk contêm variáveis, referências de array, constantes e chamadas de função, além de suas várias combinações com operadores.
Instruções Condicionais no Awk
O Awk também fornece boas instruções if semelhantes à linguagem C.
# Mesma funcionalidade que o exemplo na seção anterior, mas método de execução diferente
$ awk 'BEGIN { FS="|" } { if ( $2 ~ "Web" ) { print $1 } }' dados.txt
Desenvolvimento
A expressão booleana ($2 ~ "Web") da seção anterior estava fora do bloco; neste exemplo, o bloco ({ if ( $2 ~ "Web" ) { print $1 } }) é executado uma vez para cada linha de entrada, e usando a instrução if (if ( $2 ~ "Web" )), a instrução print é executada seletivamente. Pode ser escolhido conforme necessário.
A instrução if-else é a instrução de decisão do Awk.
Sintaxe: if (condição) then-body [else else-body]
condição: uma expressão que controla o que o resto da instrução deve fazer; quando verdadeira, o then-body é executado; quando falsa, o else-body é executado; quando 0 ou string vazia, é falso; caso contrário, é verdadeiro;
A parte else é opcional.
O Awk também pode usar operadores booleanos || (OU lógico) && (E lógico) para criar expressões booleanas mais complexas.
# Imprime linhas separadas por | onde a primeira coluna corresponde a "Sistemas" ou a segunda coluna corresponde a "Firewall"
$ awk 'BEGIN { FS="|" } ( $1 ~ "Sistemas" || $2 ~ "Firewall" ) { print }' dados.txt
Sistemas - Linux
Segurança - Firewall, Rede, Segurança Online etc.
Variáveis e Operadores no Awk
O Awk nos permite realizar operações com números inteiros e de ponto flutuante.
$ cat email.txt
De: A@a.com
Para: Teste
assunto: teste
# Linha em branco no final
# Arquivo de programa Awk
# A variável x é inicializada como 0 no bloco BEGIN
# Cada vez que uma linha em branco é encontrada, a variável x é incrementada
# Após processar todas as linhas, o bloco END é executado, imprimindo o resumo final
$ cat encontrouLinhaBranca.awk
BEGIN { x=0 }
/^$/ { x=x+1 }
END { print "Encontradas " x " linhas em branco." }
# Execução
$ awk -f encontrouLinhaBranca.awk email.txt
Encontradas 2 linhas em branco.
No Awk, ao executar operações matemáticas em variáveis, desde que a variável contenha uma string numérica válida, o Awk lida automaticamente com a etapa de conversão de string para número. Por exemplo:
# A variável x é inicializada como string, mas ainda pode usar a expressão matemática para adicionar 1 ao seu valor
$ awk 'BEGIN { x="3.5" } END { print x+1 }' dados.txt
4.5
Enquanto o Bash não suporta operações de ponto flutuante e para executar qualquer operação matemática no Bash, a expressão deve ser colocada entre "$(( ))", o Awk faz a operação automaticamente, e o código é limpo e elegante.
$ cat matematica.txt
a 2
b 13
c 5
# Calcula o quadrado da segunda coluna mais 1
$ awk '{ print ( $2^2 ) + 1 }' matematica.txt
5
170
26
Se uma variável especificada não contém um número válido e é usada em uma expressão matemática para cálculo, o Awk trata essa variável como o número 0.
# matematica.txt tem a primeira coluna como letras, calcula seu quadrado
$ awk '{ print ( $1^2 ) }' matematica.txt
0
0
0
Outra vantagem do Awk é que ele contém operadores aritméticos completos: operadores padrão de adição, subtração, multiplicação e divisão, operador de exponenciação ^, operador de módulo %, operador de pré-incremento ++i, operador de pré-decremento --i, operador de pós-incremento i++, operador de pós-decremento i--, operador de atribuição de adição +=, operador de atribuição de subtração -=, operador de atribuição de multiplicação *=, operador de atribuição de divisão /=, etc.
Variáveis Especiais no Awk
Variáveis especiais do Awk: um tipo usado para ajustar como o Awk funciona, e outro tipo para coletar informações úteis relacionadas à entrada.
Variável FS: define a sequência de caracteres que o Awk procura entre as colunas. Pode ser um único caractere, uma expressão regular ou um padrão de caractere de qualquer comprimento.
# Separado por um ou mais tabulações
FS="\t+"
# Separado por espaço em branco (um ou mais espaços, tabulações)
# Esta é na verdade a situação padrão: FS definido como um caractere de espaço, o Awk interpreta como um ou mais espaços, tabulações
FS="[[:space:]+]"
As duas variáveis a seguir geralmente não modificamos seus valores, mas os lemos para obter informações úteis relacionadas ao conteúdo de entrada.
1) Variável NF: usada para registrar o número de colunas.
$ cat dados.txt
Sistemas - Linux
Banco de Dados - PostgreSQL, MongoDB etc.
Segurança - Firewall, Rede, Segurança Online etc.
Desenvolvimento - Aplicativos Web
# Imprime apenas linhas com 3 colunas
$ awk 'NF == 3 { print }' dados.txt
Sistemas - Linux
Desenvolvimento - Aplicativos Web
# Também pode usar NF em instruções condicionais
$ awk '{ if ( NF < 4 ) { print $1":"$3 } }' dados.txt
Sistemas:Linux
Desenvolvimento:Aplicativos Web
2) Variável NR: usada para registrar o número do registro atual (o Awk define o valor desta variável como 1 para o primeiro registro).
$ cat dados.txt
Sistemas - Linux
Banco de Dados - PostgreSQL, MongoDB etc.
Segurança - Firewall, Rede, Segurança Online etc.
Desenvolvimento - Aplicativos Web
# Imprime registros após a 2ª linha, adicionando números de linha
$ awk '{ if ( NR > 2 ) { print NR".\t"$0 } }' dados.txt
3. Segurança - Firewall, Rede, Segurança Online etc.
4. Desenvolvimento - Aplicativos Web
Estruturas de Loop no Awk
O Awk tem loops for, while, do-while.
1) Loop while
Sintaxe:
while (condição)
corpo
corpo: representa qualquer instrução Awk;
condição: expressão que controla por quanto tempo o loop continua.
O processo do loop while: testa a condição, se verdadeira executa as instruções no corpo, após executar tudo uma vez, testa a condição novamente, repetindo esse processo até que a condição não seja mais verdadeira; se a condição for falsa desde o início, o corpo não será executado, e o Awk processa as instruções após o loop.
$ cat dados.txt
Sistemas - Linux
Banco de Dados - PostgreSQL, MongoDB etc.
Segurança - Firewall, Rede, Segurança Online etc.
Desenvolvimento - Aplicativos Web
# Imprime as três primeiras colunas de cada registro, com cada coluna em uma linha separada
$ awk '{ i=1; while ( i <= 3 ) { print $i; i++ }}' dados.txt
Sistemas
-
Linux
Banco de Dados
-
PostgreSQL,
Segurança
-
Firewall,
Desenvolvimento
-
Aplicativos Web
2) Loop do-while
O loop do-while é uma variante do loop while.
Sintaxe:
do
corpo
while (condição)
O loop do executa o corpo primeiro e, desde que a condição seja verdadeira, repete a execução do corpo. Portanto, o corpo será executado pelo menos uma vez.
3) Loop for
O loop for pode registrar convenientemente o número de iterações.
Sintaxe:
for ( init; condição; incremento )
corpo
As partes init, condição e incremento são expressões Awk arbitrárias, enquanto corpo representa qualquer instrução Awk.
O loop for começa executando init, se a condição for verdadeira, repete a execução do corpo e do incremento.
# Realiza o mesmo trabalho que o exemplo do loop while anterior
# Imprime as três primeiras colunas de cada linha, cada coluna em uma linha separada
$ awk '{ for ( i=1; i<=3; i++ ) print $i }' dados.txt
Sistemas
-
Linux
Banco de Dados
-
PostgreSQL,
Segurança
-
Firewall,
Desenvolvimento
-
Aplicativos Web
Arrays no Awk
No Awk, geralmente os índices de array começam em 1, não em 0.
1) Definição de array e atribuição:
meuarr[1]="um" # meuarr é criado e o primeiro elemento é "um";
meuarr[2]="123" # o segundo elemento é "123".
2) Iterando elementos do array:
for ( x in meuarr ){
print meuarr[x]
}
O código acima imprimirá cada elemento em meuarr.
Nota: aqui x é o índice, não o valor
No entanto, quando o Awk itera pelos índices do array, não segue uma ordem específica. Ou seja, não podemos determinar se a saída do código acima será:
um
123
ou
123
um
3) Arrays no Awk não precisam ter uma sequência de índices numéricos contínuos, por exemplo: podemos definir meuarr[1] e meuarr[100], sem definir os elementos do array com índices de 2 a 99.
4) Além de suportar índices numéricos, arrays no Awk também suportam índices de string, como:
meuarr["nome"]="Tom"
Essas características tornam os arrays do Awk fáceis de usar, mas às vezes podem causar confusão.
Para facilitar o gerenciamento, o Awk fornece:
1) Excluir elementos do array Awk:
delete meuarr[1]
2) Verificar se um índice de array especificado existe:
1 in meuarr
Exemplo:
$ cat dados.txt
Sistemas - Linux
Banco de Dados - PostgreSQL, MongoDB etc.
Segurança - Firewall, Rede, Segurança Online etc.
Desenvolvimento - Aplicativos Web
# Define o array meuarr no bloco BEGIN com dois elementos atribuídos;
# Verifica com if se o elemento do array com o número da linha como índice existe, se existir, imprime essa linha
$ awk 'BEGIN { meuarr[1]=1; meuarr[2]=3 } { if ( NR in meuarr) { print NR". "$0 }}' dados.txt
1. Sistemas - Linux
2. Banco de Dados - PostgreSQL, MongoDB etc.