Ubuntu Condicionais

Até agora seus scripts faziam sempre a mesma coisa, linha após linha. Com condicionais, o script passa a tomar decisões: "se o arquivo existe, faça backup; senão, avise o usuário". Esta aula mostra o if e seus parceiros, parte por parte.

Você vai aprender
  • Por que o if do Bash testa comandos, e não "verdadeiro ou falso".
  • Como usar [ ], [[ ]] e (( )) para testar arquivos, textos e números.
  • Quando trocar o if por &&, || ou case.
  • Como ler os erros mais comuns: "faltando `]'", "esperava operador unário" e "esperava número inteiro".

Antes, leia Primeiro Script e Variáveis e Argumentos. Os exemplos rodam na máquina fictícia notebook, com a usuária ana.


A ideia: todo comando diz se deu certo

Você já viu que todo comando devolve um código de saída: 0 quando deu certo e outro número quando deu errado. O if do Bash usa exatamente isso. Ele roda um comando e olha o código:

  • Código 0 → o if considera verdadeiro e executa o bloco do then.
  • Qualquer outro código → falso: pula para o else, se existir.
$ ls Documentos
acesso.log  notas.txt  projetos  relatorio.odt
$ echo $?
0                                                   « deu certo = verdadeiro
$ ls Fotos
ls: não é possível acessar 'Fotos': Arquivo ou diretório inexistente
$ echo $?
2                                                   « deu errado = falso
Ao contrário de outras linguagens

Em Python ou JavaScript, 0 significa "falso". No shell é o oposto: 0 significa sucesso. Pense em "zero problemas".


A estrutura do if

if COMANDO; then
  comandos se COMANDO deu certo
fi
if
"Se". Começa a decisão.
grep -q "^ana:" /etc/passwd
O comando testado. Aqui: procura a linha da usuária ana. O -q (quiet, "quieto") faz o grep não mostrar nada, só devolver o código.
; then
"Então". O ; separa o comando do then quando estão na mesma linha.
echo "a ana existe"
O que fazer quando o comando deu certo.
; fi
Fim do if. fi é if ao contrário.
$ if grep -q "^ana:" /etc/passwd; then echo "a ana existe"; fi
a ana existe
$ if grep -q "^joao:" /etc/passwd; then echo "o joao existe"; fi
$ echo $?
0

Na segunda vez, nada apareceu: o grep não achou o joao, devolveu 1, e o if pulou o echo. Repare que o echo $? mostra 0: um if sem else que não executou nada termina com sucesso.

Em scripts, escrevemos em várias linhas, com o bloco indentado (recuado com espaços). Assim fica mais fácil de ler:

#!/usr/bin/env bash
if grep -q "^ana:" /etc/passwd; then
  echo "A usuária ana existe."
fi

Testar condições: o comando [ ]

E quando você quer perguntar "este arquivo existe?" ou "este número é maior que 5?". Para isso existe o comando test, que tem um apelido: [. Isso mesmo: o colchete é um comando.

$ type [
[ é um comando interno do shell
$ test -f frutas.txt
$ echo $?
0                                                   « frutas.txt existe e é um arquivo
$ [ -f compras.txt ]
$ echo $?
1                                                   « compras.txt não existe
[
O comando de teste (o mesmo que test).
-f
O tipo de teste: "existe e é um arquivo comum".
"$arquivo"
O que está sendo testado. Sempre entre aspas.
]
Fecha o teste. É obrigatório e precisa de espaço antes.
Espaços são obrigatórios

Como [ é um comando, ele precisa de espaço depois, e o ] é o último argumento, com espaço antes. [-f arq] e [ -f arq] dão erro. O certo é [ -f arq ].

Seu primeiro if com teste

#!/usr/bin/env bash
arquivo="$1"

if [ -f "$arquivo" ]; then
  echo "O arquivo $arquivo existe."
else
  echo "Não encontrei $arquivo."
fi

O else ("senão") é opcional: ele roda quando o teste dá falso.

$ chmod +x verifica.sh
$ ./verifica.sh frutas.txt
O arquivo frutas.txt existe.
$ ./verifica.sh compras.txt
Não encontrei compras.txt.

Os testes mais usados

Arquivos e pastas

TesteVerdadeiro quando…Exemplo
-eO caminho existe (arquivo, pasta, qualquer coisa)[ -e ~/.bashrc ]
-fExiste e é um arquivo comum[ -f notas.txt ]
-dExiste e é uma pasta[ -d Documentos ]
-sExiste e não está vazio (tamanho maior que 0)[ -s log.txt ]
-r -w -xVocê pode ler / escrever / executar[ -x backup.sh ]
-LÉ um link simbólico[ -L /usr/bin/python3 ]

Textos (strings)

TesteVerdadeiro quando…Exemplo
"$a" = "$b"Os textos são iguais[ "$USER" = "ana" ]
"$a" != "$b"Os textos são diferentes[ "$resp" != "s" ]
-z "$a"O texto está vazio (zero)[ -z "$nome" ]
-n "$a"O texto não está vazio (non-zero)[ -n "$1" ]

Números inteiros

TesteSignificaVem do inglês
-eqigualequal
-nediferentenot equal
-ltmenor queless than
-lemenor ou igualless or equal
-gtmaior quegreater than
-gemaior ou igualgreater or equal
Para números, -gt; nunca > dentro de [ ]

Dentro de [ ], o > é um redirecionamento. Veja o estrago:

$ if [ 3 > 5 ]; then echo "3 é maior que 5?!"; fi
3 é maior que 5?!                                   « resposta errada…
$ ls 5
5                                                   « …e ainda criou um arquivo chamado "5"

O > 5 mandou a saída do teste para um arquivo "5", e o teste que sobrou ([ 3 ]) é sempre verdadeiro. Use [ 3 -gt 5 ] ou (( 3 > 5 )).

Negar e combinar

FormaSignificaExemplo
!"não": inverte o resultado[ ! -d "$pasta" ]
&& entre testes"e": os dois precisam ser verdade[ -f a ] && [ -r a ]
|| entre testes"ou": basta um ser verdade[ "$r" = s ] || [ "$r" = S ]

Várias saídas: elif e else

elif é a junção de else if, "senão, se". O Bash testa de cima para baixo e executa só o primeiro bloco verdadeiro.

#!/usr/bin/env bash
nota="$1"

if [ "$nota" -ge 7 ]; then
  echo "Aprovado"
elif [ "$nota" -ge 5 ]; then
  echo "Recuperação"
else
  echo "Reprovado"
fi
$ ./nota.sh 8
Aprovado
$ ./nota.sh 5
Recuperação                                         « 5 não é ≥ 7, mas é ≥ 5
$ ./nota.sh 3
Reprovado

Formas diferentes de testar

O Bash tem quatro jeitos de escrever um teste. Todos funcionam; cada um tem seu ponto forte.

[[ ]]: o teste moderno do Bash

O colchete duplo é uma palavra-chave do Bash (não um comando). Ele aceita variáveis sem aspas, && e || por dentro e comparação com curingas:

$ arquivo="relatorio.pdf"
$ if [[ $arquivo == *.pdf ]]; then echo "é PDF"; fi
é PDF
$ if [[ -f frutas.txt && -r frutas.txt ]]; then echo "posso ler"; fi
posso ler

(( )): contas e comparações de números

Dentro de (( )), os sinais > < == funcionam como na matemática, sem $ nas variáveis:

$ x=10
$ if (( x > 5 )); then echo "maior que 5"; fi
maior que 5

&& e ||: o if de uma linha

Para decisões curtas, você nem precisa do if:

mkdir backup
Primeiro comando.
&& echo "criada"
"E então": só roda se o anterior deu certo.
|| echo "falhou"
"Ou então": só roda se o anterior deu errado.
$ mkdir backup && echo "pasta criada" || echo "falhou"
pasta criada
$ mkdir backup && echo "pasta criada" || echo "falhou"
mkdir: backup: Arquivo existe
falhou

Qual usar?

FormaExemploMelhor quando…
if comandoif grep -q x arq; thenA pergunta é "esse comando deu certo?"
[ ] / test[ -f "$a" ]Scripts que precisam rodar em qualquer shell (sh)
[[ ]][[ $a == *.pdf ]]Scripts Bash: é o mais seguro e flexível
(( ))(( idade >= 18 ))Comparações e contas com números
&& / ||[ -d x ] || mkdir xDecisões de uma linha, sem else complexo

Missão: este simulador não tem if, mas tem &&, || e $?. Use ls relatorios || mkdir relatorios para criar a pasta só se ela não existir. Depois rode mkdir relatorios && echo ok || echo "já existe" e veja qual mensagem aparece. Confira o código com echo $?.


Escolher entre muitas opções: case

Quando uma variável pode ter vários valores, uma fila de elif fica longa. O case ("caso") compara o valor com uma lista de padrões:

#!/usr/bin/env bash
case "$1" in
  iniciar|start)
    echo "Iniciando o serviço..."
    ;;
  parar|stop)
    echo "Parando o serviço..."
    ;;
  status)
    echo "O serviço está rodando."
    ;;
  *)
    echo "Uso: $0 {iniciar|parar|status}"
    exit 1
    ;;
esac
case "$1" in
"No caso do valor de $1…"
iniciar|start)
Um padrão. A barra | aqui significa "ou". O ) fecha o padrão.
;;
Fim deste caso. O case para aqui.
*)
Qualquer outra coisa (o "senão" do case).
esac
Fim do case (case ao contrário).
$ ./servico.sh iniciar
Iniciando o serviço...
$ ./servico.sh reiniciar
Uso: ./servico.sh {iniciar|parar|status}
$ echo $?
1                                                   « o script avisou que algo deu errado

Os padrões aceitam curingas: *.jpg|*.png) pega imagens, [sS]|[sS]im) pega "s", "S", "sim" e "Sim".


Exemplo completo: um backup que confere tudo antes

Este script junta o que você aprendeu. Ele confere se recebeu um argumento, se esse argumento é uma pasta, e só então compacta. Cada erro devolve um código diferente.

#!/usr/bin/env bash
# Uso: ./backup.sh PASTA

if [ $# -ne 1 ]; then
  echo "Uso: $0 PASTA" >&2
  exit 1
fi

origem="$1"

if [ ! -d "$origem" ]; then
  echo "Erro: '$origem' não é uma pasta." >&2
  exit 2
fi

destino="backup-$(date +%F).tar.gz"

if tar -czf "$destino" "$origem"; then
  echo "Backup criado: $destino"
else
  echo "Erro: o tar falhou." >&2
  exit 3
fi
  • $# é a quantidade de argumentos; -ne 1 pergunta "é diferente de 1?".
  • >&2 manda a mensagem para a saída de erros, como fazem os comandos de verdade.
  • exit 1, exit 2… encerram o script com um código que quem chamou pode testar.
  • O último if testa o próprio tar: se ele falhar, o script avisa.
$ ./backup.sh
Uso: ./backup.sh PASTA
$ echo $?
1
$ ./backup.sh frutas.txt
Erro: 'frutas.txt' não é uma pasta.
$ echo $?
2
$ ./backup.sh Documentos
Backup criado: backup-2026-10-15.tar.gz

Quando não funciona

"faltando `]'"
$ if [ -f frutas.txt]; then echo ok; fi
bash: [: faltando `]'

O que aconteceu: faltou o espaço antes do ]. O [ recebeu frutas.txt] como uma palavra só e não achou o ] de fechamento.

Como resolver: espaço dos dois lados: [ -f frutas.txt ].

"[a: comando não encontrado"
$ if ["a" = "a"]; then echo ok; fi
[a: comando não encontrado

O que aconteceu: sem espaço depois do [, o Bash procurou um comando chamado [a.

Como resolver: [ "a" = "a" ].

"esperava operador unário"
$ nome=""
$ if [ $nome = "ana" ]; then echo oi; fi
bash: [: =: esperava operador unário

O que aconteceu: a variável estava vazia e sem aspas. O teste virou [ = "ana" ], que não faz sentido.

Como resolver: sempre coloque variáveis entre aspas dentro de [ ]: [ "$nome" = "ana" ]. Ou use [[ ]], que não tem esse problema.

"esperava número inteiro"
$ ./nota.sh dez
./nota.sh: linha 4: [: dez: esperava número inteiro
./nota.sh: linha 6: [: dez: esperava número inteiro
Reprovado

O que aconteceu: -ge só compara números inteiros. Com "dez", os dois testes deram erro (código 2, que conta como falso), e o script caiu no else. Repare que ele não parou: mostrou "Reprovado", uma resposta errada.

Como resolver: valide a entrada antes. Por exemplo: [[ $nota =~ ^[0-9]+$ ]] || { echo "Digite um número"; exit 1; }.

"erro de sintaxe próximo ao token inesperado `fi'"
$ if [ "ana" = "ana" ] then echo oi; fi
bash: erro de sintaxe próximo ao token inesperado `fi'

O que aconteceu: faltou o ; antes do then. Na mesma linha, o Bash precisa dele para saber onde o teste termina.

Como resolver: if [ ... ]; then ...; fi. Em várias linhas, o then pode ir na linha de baixo, sem ;.

O terminal mostra > e não responde
$ if [ -f frutas.txt ]; then echo ok
>

O que aconteceu: o if não foi fechado com fi. O > é o Bash pedindo o resto do comando.

Como resolver: digite fi e Enter, ou cancele com Ctrl+C.


Referência rápida

EstruturaSintaxe
if simplesif COND; then …; fi
if / elseif COND; then …; else …; fi
if / elifif C1; then …; elif C2; then …; else …; fi
Teste POSIX[ -f "$a" ] ou test -f "$a"
Teste Bash[[ $a == *.txt && -s $a ]]
Números(( a >= 10 ))
Regex[[ $a =~ ^[0-9]+$ ]]
Uma linhaCOND && SE_SIM || SE_NAO
casecase "$v" in a|b) …;; *) …;; esac

Exercícios

1. A pasta existe?

Complete para escrever "achei" se Documentos for uma pasta:

if [ Documentos ]; then echo "achei"; fi

2. Maior ou igual

Complete para testar se $idade é maior ou igual a 18:

if [ "$idade" 18 ]; then echo "maior de idade"; fi

3. Fechando o if

Complete a palavra que encerra o bloco:

if [ -z "$1" ]; then echo "faltou o argumento";

4. Criar só se faltar

Complete para criar a pasta logs apenas se ela não existir:

[ -d logs ] mkdir logs

5. Para o Bash, o que significa um comando terminar com código 0?

6. Por que [ 3 > 5 ] é perigoso?


Resumo

  • O if roda um comando: código 0 é verdadeiro, qualquer outro é falso.
  • [ ] é um comando: precisa de espaços e de variáveis entre aspas.
  • Arquivos: -e -f -d -s -x; textos: = != -z -n; números: -eq -ne -lt -le -gt -ge.
  • [[ ]] é o teste mais seguro no Bash; (( )) é o melhor para números.
  • && e || fazem decisões de uma linha; case organiza muitas opções.