Condicionais e test
Esta aula aborda as estruturas condicionais em Shell Script, com foco em if/then/fi, o comando test e seus equivalentes [ ] e [[ ]], além das diferenças entre eles. O aluno aprenderá a escrever scripts que tomam decisões baseadas em condições, com exemplos práticos e boas práticas.
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
-ae-odentro de[ ]; prefira combinar múltiplostestcom&&e||fora dos colchetes.
Referências
- Bash Manual: Conditional Constructs
- POSIX specification for test
- Bash man page (conditional expressions)
- Advanced Bash-Scripting Guide: Test Constructs
- ShellCheck - find bugs in your shell scripts
Exercícios
-
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 -
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 -
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 -
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 -
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