Nesta aula, vamos explorar técnicas fundamentais para trabalhar com números e formatação em scripts Bash. Você já deve ter usado echo para exibir mensagens, mas quando precisamos de controle fino sobre a formatação — como alinhar colunas, definir precisão decimal ou exibir datas de maneiras específicas — precisamos de ferramentas mais poderosas. Vamos mergulhar em printf, que é o comando de formatação por excelência, e também veremos como realizar cálculos aritméticos, lidar com números de ponto flutuante e formatar datas.

Dominar esses recursos eleva seus scripts de simples automações para ferramentas robustas e legíveis, capazes de gerar relatórios, logs e saídas amigáveis ao usuário. Ao final desta aula, você será capaz de criar saídas formatadas com precisão, executar cálculos complexos e manipular datas de forma flexível.

printf

O comando printf é uma ferramenta poderosa para formatar e exibir texto e números em scripts Bash. Ele é inspirado na função printf da linguagem C e oferece um controle muito maior sobre a saída do que o simples echo. A sintaxe básica é:

printf FORMATO [ARGUMENTOS...]

O FORMATO é uma string que pode conter texto literal e especificadores de formato, que começam com %. Cada especificador corresponde a um argumento fornecido. Por exemplo, %s substitui por uma string, %d por um número inteiro e %f por um número de ponto flutuante.

Um dos principais benefícios de printf é que ele não adiciona automaticamente uma nova linha ao final, como echo faz. Isso permite controlar exatamente quando a quebra de linha ocorre, usando o caractere de escape \n no formato.

Vejamos um exemplo simples:

#!/bin/bash
nome="Maria"
idade=30
printf "Nome: %s\nIdade: %d anos\n" "$nome" "$idade"

A saída será:

Nome: Maria
Idade: 30 anos

Além dos especificadores básicos, você pode incluir flags e modificadores de largura e precisão. Por exemplo, para alinhar à esquerda com largura de 10 caracteres, usa-se %-10s. Para preencher com zeros à esquerda em um número, use %05d.

Um exemplo prático de uso de printf para criar uma tabela alinhada:

#!/bin/bash
printf "%-10s %8s\n" "Produto" "Preço"
printf "%-10s %8.2f\n" "Maçã" 2.50
printf "%-10s %8.2f\n" "Banana" 1.75
printf "%-10s %8.2f\n" "Laranja" 3.20

Isso gera uma tabela com colunas alinhadas à esquerda (produto) e à direita (preço com duas casas decimais).

Formatação numérica

Em Bash, os números inteiros são geralmente tratados como inteiros de 64 bits, e a aritmética com inteiros é feita através da expansão aritmética $((...)). No entanto, para números de ponto flutuante, precisamos usar comandos externos como bc ou awk. A formatação de números é frequentemente necessária para exibir valores com uma quantidade específica de casas decimais, separadores de milhar, ou em notação científica.

O comando printf oferece especificadores para controlar a precisão de números de ponto flutuante. O especificador %f exibe um número de ponto flutuante com seis casas decimais por padrão, mas podemos alterar isso com %.2f para duas casas, por exemplo. Também podemos usar %e para notação científica e %g para uma representação mais compacta.

Vejamos alguns exemplos:

#!/bin/bash
pi=3.14159265
printf "Pi com 2 casas: %.2f\n" "$pi"
printf "Pi com 4 casas: %.4f\n" "$pi"
printf "Notação científica: %e\n" "$pi"
printf "Compacta: %g\n" "$pi"

Saída:

Pi com 2 casas: 3.14
Pi com 4 casas: 3.1416
Notação científica: 3.141593e+00
Compacta: 3.14159

Além disso, podemos usar printf para preencher números com zeros à esquerda, o que é útil para gerar sequências com largura fixa, como números de pedido ou códigos. Por exemplo, %05d formata um número com pelo menos 5 dígitos, preenchendo com zeros à esquerda.

#!/bin/bash
for i in {1..5}; do
  printf "Número do pedido: %05d\n" "$i"
done

Isso gera:

Número do pedido: 00001
Número do pedido: 00002
Número do pedido: 00003
Número do pedido: 00004
Número do pedido: 00005

Para números grandes, podemos incluir separadores de milhar, mas o printf do Bash não suporta isso diretamente. Uma solução é usar sed ou awk para adicionar os separadores, ou usar o comando numfmt disponível no coreutils.

#!/bin/bash
valor=1234567
# Usando numfmt para formatar com separador de milhar
numfmt --grouping <<< "$valor"
# Também podemos usar printf e depois um sed para inserir os separadores
printf "%d\n" "$valor" | sed ':a; s/\B[0-9]\{3\}\>/,&/; ta'

O comando numfmt é mais simples e confiável.

Datas (date)

O comando date é essencial para trabalhar com datas e horários em scripts. Ele pode exibir a data atual, formatá-la de várias maneiras, e também realizar cálculos com datas. A sintaxe básica é date [OPÇÕES] [+FORMATO].

O formato é uma string que começa com + e contém sequências de escape que começam com %. Por exemplo, %Y é o ano com quatro dígitos, %m é o mês com dois dígitos, %d é o dia do mês com dois dígitos, %H é a hora (00-23), %M é o minuto e %S é o segundo. Também temos %F que é equivalente a %Y-%m-%d (formato ISO) e %T que é %H:%M:%S.

Exemplos:

#!/bin/bash
date "+%Y-%m-%d"          # Data no formato ISO (ex.: 2025-03-23)
date "+%d/%m/%Y"          # Data no formato brasileiro (ex.: 23/03/2025)
date "+%H:%M:%S"          # Hora atual (ex.: 14:30:45)
date "+%d de %B de %Y"    # 23 de março de 2025 (mês por extenso)
date "+%s"                # Timestamp Unix (segundos desde 1970-01-01)

Além de exibir a data atual, o comando date pode ser usado para manipular datas, como calcular datas futuras ou passadas. Para isso, usamos a opção -d (ou --date) com uma string de data relativa. Por exemplo:

#!/bin/bash
# Data de amanhã
date -d "tomorrow" "+%Y-%m-%d"
# Data daqui a 30 dias
date -d "+30 days" "+%Y-%m-%d"
# Data de ontem
date -d "yesterday" "+%Y-%m-%d"
# Data há 1 mês
date -d "-1 month" "+%Y-%m-%d"

Também é possível especificar uma data base com -d e um formato de entrada com --date para interpretar strings de data em vários formatos, como "2025-03-23", "23/03/2025", "March 23, 2025", etc. Para cálculos mais complexos, podemos usar o comando date em conjunto com date -d e date +%s para converter em timestamps.

Um exemplo de cálculo de diferença entre duas datas:

#!/bin/bash
data1="2025-03-01"
data2="2025-03-23"
ts1=$(date -d "$data1" +%s)
ts2=$(date -d "$data2" +%s)
diff=$((ts2 - ts1))
dias=$((diff / 86400))
echo "Diferença em dias: $dias"

Isso é útil para calcular prazos, idade, etc.

Cálculos

Em Bash, há várias maneiras de realizar cálculos. Para inteiros, usamos a expansão aritmética $((...)) ou o comando let. Por exemplo:

#!/bin/bash
a=10
b=3
soma=$((a + b))
subtracao=$((a - b))
multiplicacao=$((a * b))
divisao=$((a / b))
modulo=$((a % b))
echo "Soma: $soma"
echo "Subtração: $subtracao"
echo "Multiplicação: $multiplicacao"
echo "Divisão inteira: $divisao"
echo "Módulo: $modulo"

A divisão inteira trunca a parte decimal, resultando em 3 para 10/3. Para obter um resultado de ponto flutuante, precisamos usar bc (calculadora de precisão arbitrária) ou awk.

O comando bc é uma calculadora poderosa que suporta operações de ponto flutuante e até mesmo funções matemáticas. Podemos usá-lo em um script da seguinte forma:

#!/bin/bash
resultado=$(echo "scale=2; 10 / 3" | bc)
echo "10 / 3 = $resultado"

A variável scale define o número de casas decimais. Também podemos usar bc -l para carregar a biblioteca matemática padrão, que inclui funções como seno, cosseno, logaritmo, etc.

Outra alternativa é o awk, que é uma linguagem de processamento de texto, mas também pode realizar cálculos de ponto flutuante. Por exemplo:

#!/bin/bash
resultado=$(awk "BEGIN {printf \"%.2f\", 10/3}")
echo "10 / 3 = $resultado"

Para cálculos mais complexos, como raiz quadrada, potência, etc., podemos usar bc -l:

#!/bin/bash
# Raiz quadrada de 16
raiz=$(echo "sqrt(16)" | bc -l)
# Potência: 2^10
potencia=$(echo "2^10" | bc -l)
echo "Raiz: $raiz"
echo "Potência: $potencia"

Além disso, o Bash suporta a expansão aritmética para operações com inteiros, mas não para ponto flutuante. Portanto, para scripts que exigem precisão, é recomendável usar bc ou awk.

Também podemos usar o comando expr para cálculos inteiros, mas é considerado obsoleto e menos eficiente que a expansão aritmética.

Um exemplo mais completo de cálculo com bc e formatação com printf:

#!/bin/bash
# Calculando juros compostos
capital=1000
taxa=0.05
anos=3
# Fórmula: montante = capital * (1 + taxa)^anos
montante=$(echo "scale=2; $capital * (1 + $taxa)^$anos" | bc -l)
printf "Montante após %d anos: R$ %.2f\n" "$anos" "$montante"

Isso demonstra a combinação de cálculo e formatação para gerar uma saída profissional.

Boas práticas

Ao trabalhar com números e formatação em Bash, algumas boas práticas podem melhorar a qualidade e a confiabilidade dos seus scripts:

  • Use printf em vez de echo quando precisar de formatação controlada, especialmente com números.
  • Para cálculos com ponto flutuante, prefira bc ou awk em vez de tentativas com inteiros.
  • Sempre defina o scale no bc para evitar resultados com muitas casas decimais.
  • Ao usar date, especifique o formato explicitamente para evitar ambiguidades.
  • Teste seus cálculos com valores de borda (zero, negativos, etc.) para garantir que os resultados sejam esperados.
  • Documente as fórmulas e formatos usados, para que outros (e você no futuro) entendam a lógica.

Referências

Exercícios

  1. Escreva um script que use printf para exibir uma tabela de 5 produtos com nome (largura 15) e preço (largura 8, com 2 casas decimais). Use dados fictícios.

    ✓ Resposta:
    #!/bin/bash
    printf "%-15s %8s\n" "Produto" "Preço"
    printf "%-15s %8.2f\n" "Arroz" 25.90
    printf "%-15s %8.2f\n" "Feijão" 8.75
    printf "%-15s %8.2f\n" "Macarrão" 4.50
    printf "%-15s %8.2f\n" "Óleo" 7.20
    printf "%-15s %8.2f\n" "Sal" 2.30
  2. Use date para exibir a data de hoje no formato "DD/MM/AAAA" e a data daqui a 45 dias no mesmo formato.

    ✓ Resposta:
    #!/bin/bash
    echo "Hoje: $(date +%d/%m/%Y)"
    echo "Daqui a 45 dias: $(date -d "+45 days" +%d/%m/%Y)"
  3. Calcule a média de três números (ex.: 7.5, 8.2, 6.9) usando bc e exiba o resultado com 2 casas decimais usando printf.

    ✓ Resposta:
    #!/bin/bash
    notas="7.5 8.2 6.9"
    media=$(echo "scale=2; ($(echo $notas | tr ' ' '+'))/3" | bc)
    printf "Média: %.2f\n" "$media"
  4. Escreva um script que receba um número inteiro e exiba ele preenchido com zeros à esquerda até 6 dígitos. Teste com o número 42.

    ✓ Resposta:
    #!/bin/bash
    numero=42
    printf "%06d\n" "$numero"
  5. Crie um script que calcule a idade de uma pessoa a partir da data de nascimento (ex.: 1995-05-15) usando date e bc ou aritmética inteira. Exiba a idade em anos completos.

    ✓ Resposta:
    #!/bin/bash
    nascimento="1995-05-15"
    hoje=$(date +%Y-%m-%d)
    # Converte para timestamps
    nasc_ts=$(date -d "$nascimento" +%s)
    hoje_ts=$(date -d "$hoje" +%s)
    diff=$((hoje_ts - nasc_ts))
    anos=$((diff / 31536000))  # 60*60*24*365
    # Ajuste para considerar anos bissextos? Aproximado
    echo "Idade: $anos anos"