Processamento de Texto com awk no Linux

O awk é uma ferramenta poderosa para processamento e formatação de texto em sistemas Unix-like. Enquanto o grep filtra texto e o sed atua como editor de fluxo, o awk se destaca como gerador de relatórios, permitindo manipular dados de forma estruturada.

Em distribuições Linux, o comando awk é geralmente um link simbólico para o gawk (GNU AWK):

# which awk
/usr/bin/awk

# ls -la /usr/bin/awk
lrwxrwxrwx 1 root root 4 Out 24 01:54 /usr/bin/awk -> gawk

Estrutura e Sintaxe

Todo comando awk é composto por padrões (patterns) e ações (actions). Os padrões determinam quando as ações serão executadas.

Tipos de padrões:

  • Expressões regulares: /admin/ para linhas contendo "admin"
  • Operadores relacionais: <, >, &&, ||
  • Operadores de correspondência: ~ (contém), !~ (não contém)

A sintaxe geral é:

awk [opções] 'BEGIN{ ações_iniciais }
padrão{ ações }
END{ ações_finais }' arquivo

O bloco BEGIN executa antes da leitura dos dados. O bloco END executa após processar todos os registros.

O processamento ocorre em três etapas:

  1. Leitura: uma linha é lida da entrada (arquivo, pipe ou stdin)
  2. Execução: os comandos são aplicados ao registro atual
  3. Repetição: o ciclo se repete até o fim da entrada

Variáveis Internas

Variável Descrição
$n O n-ésimo campo do registro atual (ex: $1 = primeiro campo)
$0 Linha inteira do registro atual
FILENAME Nome do arquivo sendo processado
FS Separador de campos (padrão: espaço)
NF Número de campos no registro atual
NR Número do registro (linha) atual, acumulado entre arquivos
FNR Número do regsitro atual, reiniciado por arquivo
OFS Separador de campos na saída (padrão: espaço)
ORS Separador de registros na saída (padrão: nova linha)
RS Separador de registros na entrada (padrão: nova linha)

Principais Opções

  • -F: define o separador de campos
  • -v: atribui valor a uma variável personalizada
  • -f: lê comandos de um arquivo de script

Trabalhando com Separadores

Por padrão, o awk usa espaços como separador. O parâmetro -F permite alterá-lo:

# echo "ALFA BETA GAMA DELTA" | awk '{print $2}'
BETA

# echo "ALFA,BETA,GAMA,DELTA" | awk -F "," '{print $2}'
BETA

# echo "ALFA|BETA|GAMA|DELTA" | awk -F "|" '{print $2}'
BETA

Também é possível definir múltiplos separadores usando colchetes:

# echo "XYZabc123def456" | awk -F[c0-9] '{print $1}'
XYZ
# echo "XYZabc123def456" | awk -F[c0-9] '{print $2}'
ab

Extraindo o endereço IP da interface de rede:

# ifconfig eth0 | grep inet | awk '{print $2}'
172.17.0.7

Operações com Campos

# cat dados.txt
4 5 6 7 8
5 6 7 8 9
6 7 8 9 10

Somando um valor ao primeiro campo de cada linha:

# awk '{print $1+10}' dados.txt
14
15
16

Acessando campos por posição relativa usando NF:

# echo "um dois tres quatro" | awk '{print $NF}'       # último campo
quatro

# echo "um dois tres quatro" | awk '{print $(NF-1)}'    # penúltimo campo
tres

# echo "um dois tres quatro" | awk '{print $(NF/2)}'    # campo do meio
dois

Calculando o percentual de uso de memória RAM:

#!/bin/bash
uso=$(free -m | awk '/Mem/{printf "%.2f%%", ($3/$2)*100}')
echo "Uso de memória: $uso"

Múltiplas Saídas e Condições

Listando usuários com UID menor que 10 e seus respectivos shells:

# awk -F ':' '$3<10{print $1 "<==>" $NF}' /etc/passwd
root<==>/bin/bash
bin<==>/sbin/nologin
daemon<==>/sbin/nologin

Com tabulação entre os campos:

# awk -F ':' '$3<10{print $1 "\t" $NF}' /etc/passwd
root    /bin/bash
bin     /sbin/nologin

Combinando condições com operadores lógicos:

# awk -F ':' '$3<10 && $NF=="/bin/bash"{print $1,$NF}' /etc/passwd
root /bin/bash

NR vs FNR

Selecionando linhas por número de registro:

# awk -F: '(NR>=3 && NR<=5){print NR, $0}' /etc/passwd
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

A diferença entre NR e FNR fica evidente ao processar múltiplos arquivos:

# awk '{print NR"\t"$1}' /etc/hostname /etc/hostname
1       servidor01
2       servidor01

# awk '{print FNR"\t"$1}' /etc/hostname /etc/hostname
1       servidor01
1       servidor01

Enquanto NR incrementa continuamente, FNR reinicia a cada novo arquivo.

Removendo a Primeira Linha da Saída

Três abordagans com ferramentas diferantes:

# route -n | grep -v ^Kernel
# route -n | sed 1d
# route -n | awk '(NR!=1){print $0}'

Expressões Regulares

Buscando linhas que contêm "root" (três formas equivalentes):

# awk -F: '/root/{print $0}' /etc/passwd
# awk -F: '/root/{print}' /etc/passwd
# awk -F: '/root/' /etc/passwd

Linhas que começam com "root":

# awk -F: '/^root/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

Linhas que terminam com "bash":

# awk -F: '/bash$/{print}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

Linhas que NÃO contêm "root":

# awk -F: '!/root/{print}' /etc/passwd

Expressões Condicionais

Sintaxe ternária: condição ? valor_se_verdadeiro : valor_se_falso

# awk -F: '{$3<10 ? classe="admin" : classe="comum"; print $1, classe}' /etc/passwd
root admin
bin admin
nginx comum

Usando if/else:

# awk -F: '{if($3<10){print "ADMIN:"$1} else{print "USER:"$1}}' /etc/passwd
ADMIN:root
ADMIN:bin
USER:nginx

Combinando condição com correspondência (~):

# awk -F: '{if($3<=5 && $NF ~ "/bin/bash"){print $1,$NF}}' /etc/passwd
root /bin/bash

Passando Variáveis Externas

Usando a opção -v ou referenciando diretamente:

# var='producao'
# awk -v env="$var" 'BEGIN{print "Ambiente:", env}'
Ambiente: producao

Saída Formatada com printf

Diferente do print, o printf requer um especificador de formato e não adiciona quebra de linha automaticamente.

Principais especificadores:

  • %c: caractere ASCII
  • %d ou %i: inteiro decimal
  • %f: número de ponto flutuante
  • %s: string
  • %%: sinal de porcentagem literal

Exemplos de formatação:

# awk -F: '{printf "%s\n", $1}' /etc/passwd
root
bin
daemon

# awk -F: '{printf "USUARIO: %s\n", $1}' /etc/passwd
USUARIO: root
USUARIO: bin

Alinhamento com modificadores de largura:

# awk -F: '{printf "%-15s%15s\n", $1, $NF}' /etc/passwd
root                /bin/bash
bin             /sbin/nologin
daemon          /sbin/nologin

O - antes do número indica alinhamento à esquerda.

Script awk Completo

Criando um arquivo de script relatorio.awk:

BEGIN {
    printf "%-20s%20s\n", "Usuario", "Shell"
    print "----------------------------------------"
    FS = ":"
}
$3 < 10 && $NF == "/bin/bash" {
    printf "%-20s%20s\n", $1, $NF
}
END {
    print "----------------------------------------"
}

Executando o script:

# awk -f relatorio.awk /etc/passwd
Usuario                          Shell
----------------------------------------
root                        /bin/bash
----------------------------------------

Tags: awk gawk shell Linux processamento de texto

Publicado em 7-4 08:21