fbpx Shell Script Avançado: Funções, Arrays e Erros no Bash (Guia) | Certificação Linux

Shell Script Avançado: Funções, Arrays, Tratamento de Erros e Boas Práticas

📅 19/07/2026 ⏱ 4 min ✍️ Uira Ribeiro
Shell Script Avançado: Funções, Arrays, Tratamento de Erros e Boas Práticas
Exam Pass App — mais de 7.000 questões LPI, offline, em 5 idiomas, disponível no Android e na App Store
Disponível no
Google Play
Disponível na
App Store

Scripts Bash são a cola da administração de sistemas Linux. Mas existe uma diferença enorme entre um script que funciona uma vez e um script que pode rodar em produção às 3h da manhã sem explodir o servidor. Este artigo cobre as técnicas que fazem essa diferença.

O Cabeçalho Obrigatório de Todo Script Sério

#!/usr/bin/env bash
set -euo pipefail

# -e : sai imediatamente se qualquer comando retornar erro
# -u : trata variáveis não definidas como erro (evita $VAZIO virar "")
# -o pipefail : propaga erro em pipes (cmd1 | cmd2 → falha se cmd1 falha)

Sem esses três flags, seu script continua em silêncio após um rm -rf que falhou ou uma variável vazia que destrói um caminho de arquivo.

Funções

#!/usr/bin/env bash
set -euo pipefail

# Convenção: funções de log com timestamp
log()  { echo "[$(date '+%Y-%m-%d %H:%M:%S')] INFO:  $*"; }
warn() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] WARN:  $*" >&2; }
die()  { echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERRO:  $*" >&2; exit 1; }

# Função com retorno de valor
soma() {
    local a=$1 b=$2     # local: variável não vaza para o escopo global
    echo $(( a + b ))
}

resultado=$(soma 3 7)
log "3 + 7 = $resultado"

# Função que verifica dependências
requer() {
    for cmd in "$@"; do
        command -v "$cmd" &>/dev/null || die "Comando não encontrado: $cmd"
    done
}

requer curl jq aws

Arrays

#!/usr/bin/env bash
set -euo pipefail

# Array indexado
servidores=("web01" "web02" "db01" "cache01")

# Iterar
for srv in "${servidores[@]}"; do
    echo "Verificando $srv..."
done

# Número de elementos
echo "Total: ${#servidores[@]}"

# Slice (índices 1 e 2)
echo "${servidores[@]:1:2}"   # → web02 db01

# Array associativo (dicionário)
declare -A config
config[host]="localhost"
config[porta]="5432"
config[banco]="producao"

for chave in "${!config[@]}"; do
    echo "$chave = ${config[$chave]}"
done

# Ler linhas de um arquivo para array
mapfile -t linhas < /etc/hosts
echo "Linhas em /etc/hosts: ${#linhas[@]}"

Processando Argumentos com getopts

#!/usr/bin/env bash
set -euo pipefail

uso() {
    cat <<EOF
Uso: $0 [-h] [-v] [-e AMBIENTE] [-n NOME]

  -h           Mostra esta ajuda
  -v           Modo verbose
  -e AMBIENTE  Ambiente (dev|stg|prod)   [obrigatório]
  -n NOME      Nome do deploy            [padrão: app]
EOF
    exit 1
}

VERBOSE=0
AMBIENTE=""
NOME="app"

while getopts ":hve:n:" opt; do
    case $opt in
        h) uso ;;
        v) VERBOSE=1 ;;
        e) AMBIENTE=$OPTARG ;;
        n) NOME=$OPTARG ;;
        :) die "Opção -$OPTARG requer argumento" ;;
        ?) die "Opção inválida: -$OPTARG" ;;
    esac
done

[[ -z "$AMBIENTE" ]] && die "-e AMBIENTE é obrigatório"
[[ "$AMBIENTE" =~ ^(dev|stg|prod)$ ]] || die "Ambiente inválido: $AMBIENTE"

echo "Deploy de '$NOME' em '$AMBIENTE'"
[[ $VERBOSE -eq 1 ]] && echo "[verbose] Detalhes adicionais aqui"

Tratamento de Erros com trap

#!/usr/bin/env bash
set -euo pipefail

TMPDIR=$(mktemp -d)

# Cleanup automático ao sair (com erro ou não)
cleanup() {
    local codigo=$?
    rm -rf "$TMPDIR"
    [[ $codigo -ne 0 ]] && echo "Script falhou com código $codigo" >&2
}
trap cleanup EXIT

# Se o script morrer por sinal (Ctrl+C, kill), limpar antes
trap 'echo "Interrompido" >&2; exit 130' INT TERM

echo "Arquivos temporários em $TMPDIR"
# ... seu trabalho aqui ...
# TMPDIR é removido automaticamente ao sair

Logging para Arquivo

#!/usr/bin/env bash
set -euo pipefail

LOGFILE="/var/log/meu-script.log"
LOGDIR=$(dirname "$LOGFILE")
mkdir -p "$LOGDIR"

# Redirecionar stdout e stderr para o log E para o terminal
exec > >(tee -a "$LOGFILE") 2>&1

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; }

log "=== Iniciando script $(basename "$0") ==="
log "Usuário: $(whoami) | PID: $$"

Verificações de Segurança Essenciais

# Verificar se está rodando como root
[[ $EUID -eq 0 ]] || die "Este script precisa ser root"

# Verificar se arquivo existe antes de usar
[[ -f "$CONFIG" ]] || die "Arquivo não encontrado: $CONFIG"

# Evitar race condition com lock file
LOCKFILE="/tmp/meu-script.lock"
exec 200>"$LOCKFILE"
flock -n 200 || die "Outra instância já está rodando"

# Validar que variável não está vazia E é numérica
[[ "${PORTA:-}" =~ ^[0-9]+$ ]] || die "PORTA deve ser numérica"

# Aspas duplas SEMPRE em variáveis (evita word splitting)
arquivo="meu arquivo com espaços.txt"
rm -f "$arquivo"   # correto
# rm -f $arquivo   # errado: vira 'rm -f meu arquivo com espaços.txt' → 4 args

Template de Script de Produção

#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
LOGFILE="/var/log/$(basename "$0" .sh).log"

exec > >(tee -a "$LOGFILE") 2>&1

log()  { echo "[$(date '+%F %T')] INFO  $*"; }
warn() { echo "[$(date '+%F %T')] WARN  $*" >&2; }
die()  { echo "[$(date '+%F %T')] ERRO  $*" >&2; exit 1; }

cleanup() { log "Finalizado (código: $?)"; }
trap cleanup EXIT

main() {
    log "Iniciando — args: $*"
    # seu código aqui
}

main "$@"

Este template já tem logging, cleanup automático, propagação de erro e passagem de argumentos para a função main. Copie, adapte e use como base para qualquer script novo.

Uira Ribeiro

Prof. Uirá Ribeiro

Chair do Board do Linux Professional Institute

Depois de anos vendo profissionais perderem horas em tarefas simples por não conhecer as ferramentas certas do Linux, decidi ensinar.
Hoje sou autor da maioria dos Materiais de Aprendizado oficiais da LPI e mentor de mais de 14.000 alunos certificados.

Conheça minha história completa →

Isso foi só uma peça. O curso ensina o caminho completo — do primeiro comando ao dia da prova.

Certificação Linux — a plataforma líder em certificações Linux no Brasil
WhatsApp