0Pricing
Linux Command Line & Bash Scripting Mastery · Aula

Funções do awk, formatação com printf e geração de relatórios

Defina funções personalizadas e use printf para gerar relatórios tabulares bem formatados a partir de fluxos de dados brutos.

Funções do awk, formatação com printf e geração de relatórios é uma aula grátis de Linux Command Line & Bash Scripting Mastery no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Linux Command Line & Bash Scripting Mastery, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

Por que funções e printf são importantes no awk

À medida que seus programas em awk crescem de comandos de uma linha para canalizações com várias etapas, dois recursos se tornam essenciais: funções definidas pelo usuário e formatação com printf.

As funções permitem encapsular lógica reutilizável — uma calculadora de porcentagens, um aparador de texto ou um conversor de unidades — para que você a escreva uma vez e a chame em qualquer lugar do mesmo programa. O printf permite controlar exatamente a aparência da saída: larguras de colunas, casas decimais, preenchimento e alinhamento.

Juntos, esses recursos transformam linhas de registros brutas em relatórios refinados e legíveis, sobre os quais engenheiros e gerentes podem tomar decisões.

  • As funções reduzem a duplicação e tornam os programas testáveis de forma isolada.
  • printf alinha os dados em colunas de largura fixa, mantendo os relatórios legíveis mesmo com comprimentos de entrada variados.
  • Ambos os recursos funcionam no POSIX awk, no gawk e no mawk — não são necessárias extensões.

Definindo uma função do usuário no awk

Uma função do usuário é declarada com a palavra-chave function, antes ou depois de quaisquer regras de padrão-ação. A sintaxe é:

function name(param1, param2,    local1, local2) {
    # body
    return value
}

Um idioma característico do awk: as variáveis locais são simplesmente parâmetros extras, separados dos demais por espaços adicionais. Não existe uma palavra-chave local — a convenção dos espaços extras indica que esses parâmetros são locais, não argumentos fornecidos pelo chamador.

  • Todas as variáveis que não forem declaradas como parâmetros são globais por padrão.
  • As funções podem chamar a si mesmas recursivamente.
  • return é opcional; sem ele, a função retorna uma cadeia vazia.
#!/usr/bin/env bash
# Demonstrate a simple awk user function
echo '10 3
7 0
100 4' | awk '
function divide(a, b,    result) {
    if (b == 0) return "ERR"
    result = a / b
    return result
}
{
    print $1 "/" $2 " = " divide($1, $2)
}
'

Funções com lógica de texto

As funções são especialmente úteis para operações repetidas com textos. Considere remover espaços em branco iniciais e finais — algo de que dados brutos de registros frequentemente precisam antes de comparações ou relatórios.

O exemplo abaixo define trim(s) usando gsub e a utiliza em cada registro, mantendo a regra principal limpa e legível.

  • gsub(regex, replacement, target) modifica target no próprio lugar e retorna a quantidade de substituições.
  • Colocar a lógica da expressão regular dentro de uma função mantém o bloco da regra concentrado na lógica de negócio.
  • Você pode fazer testes unitários passando textos criados manualmente diretamente em um bloco BEGIN.
#!/usr/bin/env bash
# trim() strips leading/trailing spaces; used to normalise CSV-like data
printf '  alice , 90 \n bob , 85 \n  carol , 92 \n' | awk -F',' '
function trim(s) {
    gsub(/^[ \t]+|[ \t]+$/, "", s)
    return s
}
{
    name  = trim($1)
    score = trim($2)
    print name, score
}
'

Introdução ao printf no awk

O printf no awk segue as mesmas convenções do C e do printf integrado do Bash. A principal diferença em relação a print é que o printf nunca adiciona uma nova linha automaticamente — você precisa adicionar \n por conta própria.

Especificadores de formato comuns:

  • %s — texto
  • %d — inteiro
  • %f — ponto flutuante
  • %e — notação científica
  • %g — a forma mais curta entre %f e %e

A largura e a precisão são controladas colocando números entre % e o especificador: %-20s alinha à esquerda em um campo de 20 caracteres; %8.2f fornece um número de ponto flutuante com largura 8 e 2 casas decimais.

#!/usr/bin/env bash
# printf format specifiers in awk
echo '' | awk '
BEGIN {
    printf "%s\n",        "plain string"
    printf "%10s\n",     "right-pad"
    printf "%-10s|\n",   "left-pad"
    printf "%8.2f\n",    3.14159
    printf "%08d\n",     42
    printf "%e\n",       123456.789
}
'

Criando um cabeçalho de relatório com printf

Um relatório refinado precisa de uma linha de cabeçalho e de uma linha separadora. O bloco BEGIN é o local natural para produzi-las — ele é executado uma vez antes que qualquer entrada seja processada.

O segredo é corresponder exatamente às larguras do cabeçalho com as larguras usadas nas linhas de dados. Definir constantes de largura em BEGIN (ou em uma função) mantém tudo sincronizado quando você ajustar as larguras das colunas posteriormente.

  • Use printf com uma cadeia separadora de hífens para desenhar a linha divisória.
  • Sempre termine as linhas do cabeçalho com \n.
  • Combine um cabeçalho em BEGIN, linhas por registro e um rodapé em END para obter uma estrutura completa de relatório.
#!/usr/bin/env bash
# Print a report header in BEGIN, data rows per-record, total in END
printf 'alice 9200 12\nbob 8750 10\ncarol 10400 14\n' | awk '
BEGIN {
    printf "%-10s %10s %6s %12s\n", "Name", "Salary", "Months", "Annual"
    printf "%s\n", "----------------------------------------------"
    total = 0
}
{
    annual = $2 * $3
    total += annual
    printf "%-10s %10d %6d %12d\n", $1, $2, $3, annual
}
END {
    printf "%s\n", "----------------------------------------------"
    printf "%-10s %10s %6s %12d\n", "TOTAL", "", "", total
}
'

Funções do usuário para lógica de formatação

Ao criar relatórios com várias colunas, é comum precisar da mesma chamada de formatação em vários lugares — por exemplo, para exibir uma barra de porcentagem ou converter bytes em uma unidade legível. Colocar isso dentro de uma função evita duplicação e facilita alterar o formato globalmente.

A função abaixo converte bytes em KB, MB ou GB e retorna uma cadeia formatada. A regra chamadora simplesmente passa $NF (o último campo) e imprime o resultado.

#!/usr/bin/env bash
# human_bytes() converts raw byte counts to KB/MB/GB strings
printf 'var.log 1024\naccess.log 2097152\ncore.dump 1073741824\ntiny.txt 512\n' | awk '
function human_bytes(n,    s) {
    if (n >= 1073741824) { s = sprintf("%.1f GB", n/1073741824) }
    else if (n >= 1048576) { s = sprintf("%.1f MB", n/1048576) }
    else if (n >= 1024)    { s = sprintf("%.1f KB", n/1024) }
    else                   { s = sprintf("%d B",    n) }
    return s
}
BEGIN { printf "%-20s %10s\n", "File", "Size"; print "------------------------------" }
{ printf "%-20s %10s\n", $1, human_bytes($2) }
'

Acumulando dados em matrizes antes de imprimir

Relatórios reais geralmente precisam de totais, médias ou classificações — valores que não podem ser calculados antes que toda a entrada tenha sido analisada. O padrão é:

  • Acumular dados em matrizes associativas durante a fase por registro.
  • Calcular valores derivados (médias, porcentagens) em END.
  • Gerar a saída formatada somente em END, para que as larguras possam se adaptar ao conjunto de dados completo.

Esse padrão de saída adiada é uma das expressões idiomáticas mais poderosas na geração de relatórios com awk. O exemplo abaixo contabiliza as quantidades de solicitações e os bytes de resposta por código de status HTTP a partir de um registro de acesso.

#!/usr/bin/env bash
# Summarise an nginx-style access log by HTTP status code
printf '127.0.0.1 200 1234\n127.0.0.1 404 512\n10.0.0.2 200 8900\n10.0.0.3 500 256\n10.0.0.4 200 4096\n10.0.0.5 404 300\n' | awk '
{
    status  = $2
    bytes   = $3
    count[status]++
    total_bytes[status] += bytes
}
END {
    printf "%-8s %8s %14s\n", "Status", "Requests", "Total Bytes"
    print  "-----------------------------------"
    for (s in count)
        printf "%-8s %8d %14d\n", s, count[s], total_bytes[s]
}
'

Funções recursivas em awk

awk oferece suporte à recursão. Um caso de uso clássico é calcular fatoriais ou gerar cadeias repetitivas (como uma linha de traços com o tamanho da largura do terminal). A recursão é menos comum em awk do que em linguagens de uso geral, mas funciona corretamente e está disponível em todas as principais implementações.

O exemplo abaixo define a função recursiva repeat(s, n) e a utiliza para desenhar linhas separadoras que correspondem automaticamente à largura da linha de dados mais larga — sem precisar de traços com tamanho fixo.

  • Evite recursão profunda em entradas grandes — awk não possui otimização de chamadas recursivas finais.
  • Para repetições simples, sprintf("%*s", n, "") com gsub(/ /, "-") é mais rápido, mas menos ilustrativo.
#!/usr/bin/env bash
# Recursive repeat() to build separator lines dynamically
awk '
function repeat(s, n,    acc) {
    if (n <= 0) return ""
    acc = s repeat(s, n-1)
    return acc
}
BEGIN {
    header = sprintf("%-15s %10s %10s", "Metric", "Current", "Target")
    sep    = repeat("-", length(header))
    print sep
    print header
    print sep
    printf "%-15s %10.1f %10.1f\n", "CPU %",     72.4, 60.0
    printf "%-15s %10.1f %10.1f\n", "Mem GB",    14.2, 16.0
    printf "%-15s %10d %10d\n",   "Open FDs", 1024,  800
    print sep
}
' /dev/null

Usando printf em um arquivo ou fluxo dentro do awk

O printf (e o print) do awk pode redirecionar a saída para arquivos ou canalizá-la para comandos do shell — diretamente de dentro do programa awk, sem envolver tudo em um subshell.

  • printf "..." > "file.txt" — grava em um arquivo (trunca uma vez e depois acrescenta dados durante a mesma execução).
  • printf "..." >> "file.txt" — acrescenta dados a um arquivo.
  • printf "..." | "sort -rn" — canaliza para um comando do shell; o awk mantém o fluxo aberto entre os registros e o fecha ao final do programa.

Um padrão comum é dividir uma única passagem por um registro em vários arquivos de saída, um por status ou por máquina, evitando varreduras repetidas de um arquivo grande.

#!/usr/bin/env bash
# Route records into per-status files using print redirection
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

printf '200 /index.html\n404 /missing\n200 /api/data\n500 /crash\n404 /lost\n' | awk -v out="$tmpdir" '
{
    file = out "/" $1 ".log"
    printf "%-6s %s\n", $1, $2 > file
}
END {
    close(file)  # flush all open handles
}
'

echo "=== 200 ==="
cat "$tmpdir/200.log"
echo "=== 404 ==="
cat "$tmpdir/404.log"

Gerando um relatório CSV com awk

Nem todos os relatórios são destinados a pessoas. Às vezes, a saída precisa ser um CSV legível por máquina, que alimentará uma planilha ou um fluxo de processamento posterior. O printf do awk lida bem com isso: defina OFS como uma vírgula ou controle cada delimitador explicitamente.

Duas regras importantes para gerar CSV robusto com awk:

  • Coloque entre aspas duplas os campos que possam conter vírgulas ou quebras de linha.
  • Escape quaisquer aspas duplas literais dentro de um campo duplicando-as: He said ""hello"".

A função csv_field(s) abaixo encapsula essa lógica de uso de aspas para que ela seja aplicada de maneira consistente a todos os campos de texto.

#!/usr/bin/env bash
# Emit a valid CSV report from space-separated input
printf 'alice engineer 95000\nbob "sales,mgr" 82000\ncarol developer 110000\n' | awk '
function csv_field(s,    safe) {
    safe = s
    gsub(/"/, "\"\"" , safe)   # double any embedded quotes
    return "\"" safe "\""       # wrap in quotes
}
BEGIN { print "Name,Role,Salary" }
{
    printf "%s,%s,%d\n", csv_field($1), csv_field($2), $3
}
'

Do início ao fim: um relatório completo de registro de acesso

Este exemplo final reúne tudo: funções definidas pelo usuário, formatação com printf, acumulação em matrizes e um cabeçalho/rodapé estruturado. A entrada é um registro simplificado de acesso à web; a saída é uma tabela-resumo legível, com totais por método e uma linha de total geral.

Principais técnicas utilizadas:

  • count[method]++ e bytes[method] += size acumulam estatísticas por método em uma única passagem.
  • human_bytes() (de uma seção anterior) converte totais de bytes.
  • Usar printf com larguras correspondentes no cabeçalho, nos dados e no rodapé garante que a tabela permaneça alinhada independentemente do tamanho da entrada.
  • O bloco END percorre a matriz com for (k in arr) e gera a saída ordenada por meio de um fluxo para sort.
#!/usr/bin/env bash
# Full access log report: method breakdown with human-readable bytes
printf 'GET /index 200 4096\nPOST /api 201 512\nGET /img 200 102400\nDELETE /item 204 0\nPOST /login 401 256\nGET /style 200 8192\n' | awk '
function human_bytes(n,    s) {
    if (n >= 1048576) s = sprintf("%.1f MB", n/1048576)
    else if (n >= 1024) s = sprintf("%.1f KB", n/1024)
    else s = sprintf("%d B", n)
    return s
}
{
    method = $1
    size   = $4
    count[method]++
    bytes[method] += size
    grand_count++
    grand_bytes += size
}
END {
    fmt = "%-10s %8s %15s\n"
    sep = "----------------------------------"
    printf fmt, "Method", "Requests", "Bytes"
    print sep
    for (m in count)
        printf "%-10s %8d %15s\n", m, count[m], human_bytes(bytes[m])
    print sep
    printf "%-10s %8d %15s\n", "TOTAL", grand_count, human_bytes(grand_bytes)
}
'

Verificação de conhecimentos: variáveis locais em funções awk

Qual das opções a seguir declara corretamente result como uma variável local dentro de uma função awk, seguindo a convenção POSIX?

Recapitulação da lição: funções awk, printf e geração de relatórios

Nesta lição, você aprendeu a escrever programas awk de qualidade de produção que geram relatórios formatados a partir de fluxos de dados brutos. Veja o que deve levar desta lição:

  • As funções definidas pelo usuário são declaradas com function name(params, locals). O espaço extra antes dos parâmetros das variáveis locais é uma convenção POSIX — não existe uma palavra-chave local.
  • printf oferece controle preciso sobre a saída: largura (%10s), alinhamento (%-10s) e precisão (%8.2f). Lembre-se de adicionar \n explicitamente.
  • Use BEGIN para gerar cabeçalhos e separadores, regras por registro para acumular dados e END para calcular totais e imprimir o relatório concluído.
  • Redirecione a saída de printf para arquivos (> file) ou fluxos de processamento (| "sort") de dentro do awk para dividir relatórios ou pós-processar a saída.
  • Coloque os campos de texto em uma função auxiliar csv_field() ao gerar CSV, para lidar com segurança com vírgulas e aspas incorporadas.
  • Vale a pena manter em uma biblioteca pessoal de awk as funções que convertem unidades (human_bytes), repetem caracteres (repeat) ou higienizam cadeias de texto (trim, csv_field) — elas podem ser combinadas facilmente em diferentes projetos.

Perguntas Frequentes

A aula “Funções do awk, formatação com printf e geração de relatórios” é grátis?

Sim — o texto completo de “Funções do awk, formatação com printf e geração de relatórios” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Linux Command Line & Bash Scripting Mastery, atualize para CoddyKit PRO. O curso de Linux Command Line & Bash Scripting Mastery inclui 4 aulas no total.

O que vou aprender em “Funções do awk, formatação com printf e geração de relatórios”?

Defina funções personalizadas e use printf para gerar relatórios tabulares bem formatados a partir de fluxos de dados brutos. Você pratica Linux Command Line & Bash Scripting Mastery com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Linux Command Line & Bash Scripting Mastery?

Nenhuma experiência prévia é necessária. Linux Command Line & Bash Scripting Mastery no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Funções do awk, formatação com printf e geração de relatórios”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Linux Command Line & Bash Scripting Mastery?

Sim. Cada aula de Linux Command Line & Bash Scripting Mastery inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Registros, campos e separadores personalizados no awk
  2. Padrões, intervalos e blocos BEGIN/END
  3. Agregação com matrizes e agrupamento no awk
  4. Funções do awk, formatação com printf e geração de relatórios
← Voltar para Linux Command Line & Bash Scripting Mastery