Condicionais são fundamentais em qualquer linguagem de programação, e no Shell Script não é diferente. Elas permitem que seu script tome decisões baseadas em resultados de comandos, valores de variáveis ou propriedades de arquivos. Nesta aula, vamos explorar as principais formas de implementar condicionais no Bash: a estrutura if/then/fi, o comando test e os operadores [ ] e [[ ]]. Compreender as diferenças entre essas abordagens é essencial para escrever scripts robustos e portáveis.

O Bash oferece várias maneiras de avaliar expressões condicionais. Embora o comando test e os colchetes simples [ ] sejam equivalentes e amplamente compatíveis com o POSIX, os colchetes duplos [[ ]] são uma extensão do Bash que fornece mais recursos e segurança. Vamos detalhar cada um deles.

if/then/fi

A estrutura básica de um condicional em Shell Script é if ... then ... fi. O if executa um comando (ou uma lista de comandos) e, se o código de saída for zero (indicando sucesso), executa os comandos dentro do bloco then. Caso contrário, pode-se usar else ou elif para tratar outras condições.

A sintaxe geral é:

if comando; then
    # comandos se comando retornou 0
elif outro_comando; then
    # comandos se outro_comando retornou 0
else
    # comandos se nenhum dos anteriores retornou 0
fi

Note que o then pode estar na mesma linha do if separado por ponto e vírgula, ou na linha seguinte. O importante é que fi fecha o bloco.

Exemplo prático:

#!/bin/bash
# Verifica se um arquivo existe e é legível
if [ -r "/etc/passwd" ]; then
    echo "Arquivo /etc/passwd existe e é legível."
else
    echo "Arquivo /etc/passwd não está acessível."
fi

Neste exemplo, usamos o comando [ ] (equivalente ao test) com a opção -r para verificar se o arquivo é legível. O if avalia o código de saída do comando dentro dos colchetes.

test e [ ]

O comando test é um utilitário padrão do POSIX que avalia expressões condicionais e retorna 0 (verdadeiro) ou 1 (falso). Ele pode ser invocado como test expressão ou, de forma mais comum, usando colchetes simples: [ expressão ]. Note que é obrigatório haver espaços após o [ e antes do ].

O test suporta diversos operadores para comparar números, strings e arquivos. Alguns dos mais comuns:

  • Comparação de números: -eq, -ne, -lt, -le, -gt, -ge
  • Comparação de strings: = (igual), != (diferente), -z (string vazia), -n (string não vazia)
  • Testes de arquivo: -e (existe), -f (arquivo regular), -d (diretório), -r (legível), -w (gravável), -x (executável)

Exemplo:

#!/bin/bash
# Comparação de números
x=5
y=10
if test $x -lt $y; then
    echo "$x é menor que $y"
fi

# Equivalente com [ ]
if [ $x -lt $y ]; then
    echo "$x é menor que $y"
fi

Observe que as variáveis são expandidas antes da avaliação. Por isso, é importante usar aspas duplas quando houver risco de espaços ou caracteres especiais, para evitar erros de sintaxe. Por exemplo:

nome="João Silva"
if [ "$nome" = "João Silva" ]; then
    echo "Nome correto"
fi

Sem as aspas, o comando se tornaria [ João Silva = João Silva ], que causaria um erro porque João e Silva seriam tratados como argumentos separados.

[[ ]] (bash)

O Bash fornece uma versão melhorada dos colchetes: [[ expressão ]]. Diferente de [ ], [[ ]] é uma palavra-chave interna do Bash (não um comando externo) e oferece vantagens significativas:

  • Não requer aspas para variáveis em comparações de strings, pois o tratamento de palavras é mais inteligente.
  • Suporta operadores adicionais como && (E lógico), || (OU lógico) e ! (NÃO) dentro dos colchetes.
  • Permite o uso de expressões regulares com o operador =~.
  • Não faz expansão de pathnames (globbing) dentro dos colchetes, o que evita surpresas.

Exemplos:

#!/bin/bash
# Comparação de strings sem aspas
nome="João Silva"
if [[ $nome = "João Silva" ]]; then
    echo "Nome correto"
fi

# Uso de && e ||
idade=25
if [[ $idade -gt 18 && $idade -lt 65 ]]; then
    echo "Adulto em idade ativa"
fi

# Expressão regular
if [[ "abc123" =~ ^[a-z]+[0-9]+$ ]]; then
    echo "String corresponde ao padrão"
fi

Note que em [[ ]], os operadores de comparação numérica são os mesmos (-eq, -lt, etc.), mas também é possível usar < e > para comparação lexicográfica de strings.

Diferenças

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

Característica test / [ ] [[ ]]
Tipo Comando externo (ou built-in em alguns shells) Palavra-chave interna do Bash
Portabilidade POSIX, funciona em todos os shells Apenas Bash, KornShell e Zsh
Variáveis sem aspas Propenso a erros se a variável contiver espaços Seguro, não requer aspas
Operadores lógicos -a (E), -o (OU) (menos intuitivos) &&, ||, !
Expressões regulares Não suporta Suporta com =~
Globbing Expande padrões como * e ? Não expande (trata como literal)

Boas práticas:

  • Em scripts que precisam ser portáveis (executados em diferentes shells), prefira [ ] com aspas nas variáveis.
  • Em scripts exclusivamente Bash, use [[ ]] para maior segurança e legibilidade.
  • Evite usar -a e -o dentro de [ ]; prefira combinar múltiplos test com && e || fora dos colchetes.

Referências

Exercícios

  1. Escreva um script que verifica se o usuário atual é 'root' (UID 0). Se for, exiba "Você é root"; caso contrário, exiba "Você não é root". Use [ ].

    ✓ Resposta:
    #!/bin/bash
    if [ "$(id -u)" -eq 0 ]; then
        echo "Você é root"
    else
        echo "Você não é root"
    fi
  2. Crie um script que recebe um nome de arquivo como argumento e verifica se ele existe e é um diretório. Use [[ ]].

    ✓ Resposta:
    #!/bin/bash
    if [[ -d "$1" ]]; then
        echo "$1 é um diretório."
    else
        echo "$1 não é um diretório ou não existe."
    fi
  3. Escreva um script que compara duas strings fornecidas como argumentos e exibe se são iguais ou diferentes. Use test.

    ✓ Resposta:
    #!/bin/bash
    if test "$1" = "$2"; then
        echo "As strings são iguais."
    else
        echo "As strings são diferentes."
    fi
  4. Crie um script que verifica se uma variável $NUM é maior que 10 e menor que 20. Use [[ ]] com operadores lógicos.

    ✓ Resposta:
    #!/bin/bash
    NUM=15
    if [[ $NUM -gt 10 && $NUM -lt 20 ]]; then
        echo "$NUM está entre 10 e 20."
    else
        echo "$NUM não está entre 10 e 20."
    fi
  5. Escreva um script que verifica se o primeiro argumento corresponde a um padrão de e-mail simples (contém '@' e um ponto). Use [[ ]] com expressão regular.

    ✓ Resposta:
    #!/bin/bash
    if [[ "$1" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
        echo "E-mail válido."
    else
        echo "E-mail inválido."
    fi