Nesta aula, vamos explorar as estruturas condicionais no Shell Script, fundamentais para tomar decisões e controlar o fluxo de execução dos scripts. Começaremos com o clássico if/then/fi, passando pelo comando test e os colchetes [ ] e [[ ]], até entender as diferenças entre essas formas. Ao final, você será capaz de escrever condições complexas e saber qual sintaxe utilizar em cada contexto.

As condicionais permitem que o script execute comandos diferentes dependendo de condições como existência de arquivos, comparação de strings ou números, e saídas de comandos. O Bash oferece múltiplas maneiras de expressar essas condições, cada uma com suas particularidades.

if/then/fi

A estrutura básica de uma condicional em Shell Script é o bloco if/then/fi. A sintaxe geral é:

if comando; then
    comandos_se_verdadeiro
fi

O if executa o comando especificado e verifica seu código de saída. Se o código de saída for 0 (sucesso), os comandos dentro do then são executados. Caso contrário, o script continua após o fi (que é "if" ao contrário). É possível adicionar elif e else para múltiplas condições.

Exemplo prático: verificar se um arquivo existe.

#!/bin/bash
if ls /etc/passwd > /dev/null 2>&1; then
    echo "Arquivo /etc/passwd existe"
fi

Neste exemplo, o comando ls é executado; se bem-sucedido, a mensagem é exibida. Redirecionamos a saída para /dev/null para não poluir o terminal.

test e [ ]

O comando test avalia uma expressão e retorna 0 (verdadeiro) ou 1 (falso). Ele é frequentemente usado com if. A sintaxe é:

test expressão
# ou, de forma equivalente:
[ expressão ]

Os colchetes [ ] são um sinônimo do comando test, mas exigem espaços ao redor da expressão. Exemplos comuns:

  • test -f arquivo ou [ -f arquivo ]: verdadeiro se arquivo for um arquivo regular.
  • test "$a" = "$b" ou [ "$a" = "$b" ]: compara strings.
  • test "$x" -gt 5 ou [ "$x" -gt 5 ]: compara números (maior que).

Exemplo prático:

#!/bin/bash
diretorio="/tmp"
if [ -d "$diretorio" ]; then
    echo "$diretorio é um diretório"
fi

Note que as variáveis são sempre entre aspas duplas para evitar problemas com espaços ou caracteres especiais.

[[ ]] (bash)

O Bash oferece uma versão estendida e mais segura dos colchetes: [[ ]]. Essa construção é uma palavra-chave do Bash, não um comando externo, e oferece vantagens como:

  • Não requer aspas em variáveis em expressões de string (embora ainda seja boa prática usar).
  • Suporta operadores adicionais: =~ para expressões regulares, && e || dentro dos colchetes, entre outros.
  • Não faz expansão de palavras (word splitting) ou globbing nos operandos, o que evita erros comuns.

Sintaxe:

if [[ expressão ]]; then
    comandos
fi

Exemplo com expressão regular:

#!/bin/bash
email="usuario@exemplo.com"
if [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
    echo "Email válido"
fi

Exemplo com operadores lógicos:

#!/bin/bash
idade=25
if [[ $idade -ge 18 && $idade -le 60 ]]; then
    echo "Adulto"
fi

Diferenças

As principais diferenças entre [ ] e [[ ]] são:

  • Portabilidade: [ ] é POSIX, funciona em qualquer shell (sh, bash, zsh). [[ ]] é específico do Bash (e alguns shells modernos como Zsh e Ksh).
  • Segurança: [[ ]] evita problemas com variáveis vazias ou com espaços, pois não realiza word splitting. Por exemplo, [ $var = "valor" ] quebra se $var estiver vazia ou contiver espaços; já [[ $var = "valor" ]] funciona corretamente mesmo sem aspas (embora seja recomendado usar aspas).
  • Operadores: [[ ]] permite &&, ||, <, > (para strings, comparação lexicográfica) e =~ para regex. Em [ ], os operadores lógicos devem ser -a (and) e -o (or), e a comparação de strings usa = e != apenas.
  • Expressões regulares: Apenas [[ ]] suporta o operador =~ para casamento de padrões regex.

Exemplo comparativo:

#!/bin/bash
var=""
# Com [ ] isso gera erro se var estiver vazia:
if [ $var = "teste" ]; then  # erro: argumento faltando
    echo "igual"
fi

# Com [[ ]] funciona:
if [[ $var = "teste" ]]; then
    echo "igual"
fi

Recomenda-se usar [[ ]] em scripts Bash quando a portabilidade não for uma exigência, pois é mais seguro e expressivo. Para scripts que precisam rodar em ambientes POSIX (como /bin/sh), use [ ] com cuidado com as aspas.

Boas práticas

  • Sempre coloque variáveis entre aspas duplas dentro de [ ] para evitar erros com espaços ou valores vazios.
  • Prefira [[ ]] em scripts Bash para maior clareza e menos surpresas.
  • Use (( )) para aritmética inteira, que é mais legível que -gt, -lt, etc.
  • Evite usar -a e -o dentro de [ ]; prefira usar múltiplos if ou [[ ]] com && e ||.

Referências

Exercícios

  1. Escreva um script que verifique se o arquivo "/etc/hosts" existe e, se existir, exiba seu conteúdo com cat.

    ✓ Resposta:
    #!/bin/bash
    if [ -f "/etc/hosts" ]; then
        cat "/etc/hosts"
    fi
  2. Escreva um script que pergunte ao usuário um número e diga se ele é maior, menor ou igual a 10. Use [[ ]] e operadores relacionais (-gt, -lt, -eq).

    ✓ Resposta:
    #!/bin/bash
    read -p "Digite um número: " num
    if [[ $num -gt 10 ]]; then
        echo "Maior que 10"
    elif [[ $num -lt 10 ]]; then
        echo "Menor que 10"
    else
        echo "Igual a 10"
    fi
  3. Escreva um script que receba um nome de arquivo como argumento e verifique se ele é um arquivo regular, um diretório ou não existe. Use [ ] e operadores -f, -d.

    ✓ Resposta:
    #!/bin/bash
    if [ $# -eq 0 ]; then
        echo "Uso: $0 <arquivo>"
        exit 1
    fi
    arquivo="$1"
    if [ -f "$arquivo" ]; then
        echo "É um arquivo regular"
    elif [ -d "$arquivo" ]; then
        echo "É um diretório"
    else
        echo "Não existe"
    fi
  4. Escreva um script que use [[ ]] com o operador =~ para verificar se uma string fornecida pelo usuário é um número inteiro (apenas dígitos).

    ✓ Resposta:
    #!/bin/bash
    read -p "Digite um número: " entrada
    if [[ "$entrada" =~ ^[0-9]+$ ]]; then
        echo "É um número inteiro"
    else
        echo "Não é um número inteiro"
    fi
  5. Reescreva o exercício 2 usando [ ] e operadores -a (and) e -o (or) para combinar condições, mas sem usar elif. Dica: use múltiplos if.

    ✓ Resposta:
    #!/bin/bash
    read -p "Digite um número: " num
    if [ "$num" -gt 10 ]; then
        echo "Maior que 10"
    fi
    if [ "$num" -lt 10 ]; then
        echo "Menor que 10"
    fi
    if [ "$num" -eq 10 ]; then
        echo "Igual a 10"
    fi