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.
- Por que o
ifdo Bash testa comandos, e não "verdadeiro ou falso". - Como usar
[ ],[[ ]]e(( ))para testar arquivos, textos e números. - Quando trocar o
ifpor&&,||oucase. - 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→ oifconsidera verdadeiro e executa o bloco dothen. - 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
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 dothenquando estão na mesma linha. - echo "a ana existe"
- O que fazer quando o comando deu certo.
- ; fi
- Fim do if.
fiéifao 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.
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
| Teste | Verdadeiro quando… | Exemplo |
|---|---|---|
-e | O caminho existe (arquivo, pasta, qualquer coisa) | [ -e ~/.bashrc ] |
-f | Existe e é um arquivo comum | [ -f notas.txt ] |
-d | Existe e é uma pasta | [ -d Documentos ] |
-s | Existe e não está vazio (tamanho maior que 0) | [ -s log.txt ] |
-r -w -x | Você pode ler / escrever / executar | [ -x backup.sh ] |
-L | É um link simbólico | [ -L /usr/bin/python3 ] |
Textos (strings)
| Teste | Verdadeiro 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
| Teste | Significa | Vem do inglês |
|---|---|---|
-eq | igual | equal |
-ne | diferente | not equal |
-lt | menor que | less than |
-le | menor ou igual | less or equal |
-gt | maior que | greater than |
-ge | maior ou igual | greater or equal |
-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
| Forma | Significa | Exemplo |
|---|---|---|
! | "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?
| Forma | Exemplo | Melhor quando… |
|---|---|---|
if comando | if grep -q x arq; then | A 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 x | Decisõ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 (
caseao 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 1pergunta "é diferente de 1?".>&2manda 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
iftesta o própriotar: 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
$ 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 ].
$ 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" ].
$ 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.
$ ./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; }.
$ 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 ;.
> 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
| Estrutura | Sintaxe |
|---|---|
| if simples | if COND; then …; fi |
| if / else | if COND; then …; else …; fi |
| if / elif | if 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 linha | COND && SE_SIM || SE_NAO |
| case | case "$v" in a|b) …;; *) …;; esac |
Exercícios
1. A pasta existe?
Complete para escrever "achei" se Documentos for uma pasta:
2. Maior ou igual
Complete para testar se $idade é maior ou igual a 18:
3. Fechando o if
Complete a palavra que encerra o bloco:
4. Criar só se faltar
Complete para criar a pasta logs apenas se ela não existir:
5. Para o Bash, o que significa um comando terminar com código 0?
6. Por que [ 3 > 5 ] é perigoso?
Resumo
- O
ifroda 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;caseorganiza muitas opções.