Trabalhando com números e formatação
Nesta aula, você aprenderá a manipular números e formatar saídas em scripts Bash usando printf, formatação numérica, manipulação de datas com o comando date e cálculos aritméticos com expansão aritmética e o comando bc. O conteúdo é essencial para gerar relatórios, logs e saídas profissionais em seus scripts.
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 anosAlé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.20Isso 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.14159Alé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"
doneIsso 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: 00005Para 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
printfem vez deechoquando precisar de formatação controlada, especialmente com números. - Para cálculos com ponto flutuante, prefira
bcouawkem vez de tentativas com inteiros. - Sempre defina o
scalenobcpara 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
- Bash Builtins (printf) - GNU Bash Manual
- printf: format and print data - GNU Coreutils
- date(1) - Linux manual page
- bc - An arbitrary precision calculator language
- GNU Awk User's Guide
- numfmt - Convert numbers from/to human-readable strings
Exercícios
- Escreva um script que use
printfpara 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 - Use
datepara 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)" - Calcule a média de três números (ex.: 7.5, 8.2, 6.9) usando
bce exiba o resultado com 2 casas decimais usandoprintf.✓ 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" - 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" - Crie um script que calcule a idade de uma pessoa a partir da data de nascimento (ex.: 1995-05-15) usando
dateebcou 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"