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:
- Leitura: uma linha é lida da entrada (arquivo, pipe ou stdin)
- Execução: os comandos são aplicados ao registro atual
- 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%dou%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
----------------------------------------