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

Especialista Linux com mais de 20 anos de experiência.
Autor de 5 livros e mentor de mais de 14.000 alunos certificados.
20 certificações de alto nível, incluindo LPIC-3, CKA, RHCE e AWS Solutions Architect.

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