Codigos de Saida: Usando $? e && ||

Codigos de Saida: Usando $? e && ||

O Que Voce Vai Aprender

  • A ideia de um codigo de saida (exit status) que sinaliza sucesso ou falha
  • Como verificar o resultado do comando anterior com $?
  • Como ramificar com "se teve sucesso" e "se falhou" usando && e ||
  • Um primeiro passo para tratar erros corretamente em shell scripts

Resumo Rapido

  • Todo comando retorna um numero quando termina (0 significa sucesso, qualquer outra coisa significa falha)
  • Quer ver o ultimo resultado? echo $?
  • Executar proximo em caso de sucesso -> &&
  • Executar proximo em caso de falha -> ||

1. O Que e um Codigo de Saida?

Conclusao: Um codigo de saida e o numero que um comando retorna. 0 significa sucesso; 1 a 255 significam falha.

Lina: Senpai, quando eu executo um comando, a saida aparece na tela. Mas como eu sei se ele realmente teve sucesso ou falhou?
Veterano Linny: Otima pergunta. Todo comando sempre retorna um numero quando termina. Chamamos isso de codigo de saida (ou exit code).
Lina: Um numero? Mas eu nao vejo nenhum na tela.
Veterano Linny: Ele fica oculto da visualizacao normal. A regra e simples: 0 significa sucesso, qualquer coisa diferente de 0 significa falha. Esse unico numero diz se o comando funcionou.

A regra basica

Numero Significado
0 Sucesso
1-255 Falha (algum problema)

"0 significa sucesso" e contraintuitivo, entao fixe isso primeiro.

2. Por Que o Codigo de Saida Importa?

Conclusao: O codigo de saida e o que permite automatizar "executar o proximo passo apenas quando este teve sucesso."

Lina: Ok, um numero e retornado. Mas para que ele serve de verdade?
Veterano Linny: Imagine uma tarefa como "deletar os arquivos antigos apenas apos o backup ter sucesso." Deleta-los apos um backup falho seria um desastre, certo?
Lina: Com certeza! Eu gostaria que a proxima acao dependesse de a primeira ter funcionado.
Veterano Linny: Exatamente. Essa decisao depende do codigo de saida. E a base da automacao e do shell scripting.

Julgar sucesso apenas pelo que e impresso na tela e arriscado. Um comando pode falhar mesmo quando nenhum texto "Error" aparece. Confiar no codigo de saida legivel por maquina e muito mais confiavel.

3. Verificar o Resultado com $?

Conclusao: $? contem o codigo de saida do ultimo comando. Use echo $? para ve-lo.

O codigo de saida do comando que voce acabou de executar e armazenado na variavel especial $?.

$ ls /etc
hosts  passwd  ...
$ echo $?
0
Lina: Recebi 0! Entao ls teve sucesso.
Veterano Linny: Certo. Agora vamos faze-lo falhar de proposito. Tente executar ls em um caminho que nao existe.
$ ls /not-exist
ls: cannot access '/not-exist': No such file or directory
$ echo $?
2
Lina: Dessa vez recebi 2. Um numero diferente do anterior!
Veterano Linny: Em caso de falha, retorna algo diferente de 0. ls retorna 2 para erro de "arquivo nao encontrado". Voce nao precisa decorar os numeros exatos — apenas se e 0 ou nao.

$? guarda apenas o resultado do comando imediatamente anterior. Executar echo $? duas vezes seguidas faz com que o segundo mostre "o codigo de saida do primeiro echo (que teve sucesso, entao 0)." Verifique apenas uma vez.

4. Encadear "em caso de sucesso" com &&

Conclusao: cmd1 && cmd2 executa cmd2 apenas quando cmd1 tem sucesso (retorna 0).

&& significa "se o lado esquerdo tiver sucesso, execute o lado direito tambem."

$ mkdir backup && cp data.txt backup/
Lina: Entao isso significa "executar cp apenas se mkdir tiver sucesso"?
Veterano Linny: Exatamente. Se mkdir backup falhar (digamos, voce nao tem permissao para cria-lo), cp nao sera executado. Use quando um passo depende do anterior ter sucesso.
# Executar testes apenas se o build tiver sucesso
$ make && make test

# Listar o conteudo apenas se o cd tiver sucesso
$ cd /var/log && ls

Pense em && como "prosseguir quando a pre-condicao for atendida." Ele encadeia passos com seguranca onde voce quer parar se algo falhar.

5. Encadear "em caso de falha" com ||

Conclusao: cmd1 || cmd2 executa cmd2 apenas quando cmd1 falha. Use para tratamento de erros.

|| e o oposto de &&: significa "se o lado esquerdo falhar, execute o lado direito."

$ cd /var/log || echo "Nao foi possivel entrar no diretorio"
Lina: Entao se cd falhar, imprime uma mensagem. E se tiver sucesso, nenhuma mensagem?
Veterano Linny: Correto. Se cd tiver sucesso, o echo nunca executa. || e frequentemente usado como uma rede de seguranca para quando as coisas dao errado.
# Sugerir instalacao se um comando estiver faltando
$ which jq || echo "jq nao esta instalado. Por favor, instale-o."

# Sair do script se o passo falhar
$ cp data.txt backup/ || exit 1

&& vs || resumo visual

cmd1 && cmd2   ->  cmd2 executa se cmd1 [tiver sucesso]
cmd1 || cmd2   ->  cmd2 executa se cmd1 [falhar]

Lembre-se: "&& prossegue em caso de sucesso," "|| prossegue em caso de falha."

6. Combinando && e ||

Conclusao: cmd && em-sucesso || em-falha escreve "faca A em caso de sucesso, B em caso de falha" em uma linha.

Encadear && e || permite agir de forma diferente em caso de sucesso ou falha.

$ ping -c1 example.com > /dev/null && echo "Conexao OK" || echo "Conexao NG"
Lina: Entao eu posso escrever "imprimir OK em caso de sucesso, NG em caso de falha" em uma unica linha!
Veterano Linny: Sim — mas ha uma ressalva. Com esse padrao, se a acao de sucesso (echo Conexao OK) falhar, a acao de falha tambem executa. E aceitavel para mensagens simples, mas para algo complexo, um if e mais seguro.

A && B || C nao e estritamente identico a "if A then B else C." Se B falhar, C tambem executa. Quando voce precisa de ramificacao confiavel, use uma instrucao if (veja o artigo relacionado).

7. Armadilhas Comuns de Iniciantes

Conclusao: Os erros faceis sao inverter "0 significa sucesso" e ler $? tarde demais.

7-1. Lembrar "0 significa sucesso" ao contrario

Lina: Honestamente, "0 significa sucesso" ainda parece estranho para mim...
Veterano Linny: Todo mundo sente isso. Pense "0 = sem erros = zero problemas" e isso fixa. Imagine como uma contagem de erros, nao uma nota de prova.

7-2. Ler $? tarde demais

$ ls /not-exist
$ pwd            # <- um comando extra escapou
$ echo $?        # isto mostra o resultado de pwd (0, sucesso)

Verifique $? logo apos o comando que voce quer verificar. Qualquer comando entre eles sobrescreve $?.

7-3. Retornando um codigo de saida voce mesmo

Quando voce quer que um script ou comando reporte sucesso ou falha ao chamador, use exit.

exit 0   # encerrar como sucesso
exit 1   # encerrar como falha

Se voce chamar exit sem um numero, ele retorna o codigo de saida do ultimo comando como esta.

8. Exercicios Praticos

Conclusao: Tres exercicios — verificar, executar em sucesso, executar em falha — para praticar $?, && e ||.

Lina: Entendi os conceitos! Quero tentar eu mesma.
Veterano Linny: Otimo — preparei tres exercicios. Tente-os no seu terminal.

Exercicio 1: Execute qualquer comando (ex.: ls), depois imprima seu codigo de saida logo em seguida.

Mostrar dica

O ultimo resultado esta em $?.

Resposta exemplo
$ ls
$ echo $?

Exercicio 2: Imprima "Criado" apenas quando mkdir test-dir tiver sucesso.

Mostrar dica

"Executar proximo em caso de sucesso" e &&.

Resposta exemplo
$ mkdir test-dir && echo "Criado"

Exercicio 3: Tente fazer cd em um diretorio que nao existe e imprima "Nao foi possivel mover" se falhar.

Mostrar dica

"Executar proximo em caso de falha" e ||.

Resposta exemplo
$ cd /not-exist || echo "Nao foi possivel mover"

9. Modelos para Copiar e Colar

Conclusao: Mantenha os padroes comuns — verificar, em sucesso, em falha, ramificar e sair — ao alcance.

Padroes comuns para ter a mao

# Verificar o ultimo codigo de saida
echo $?

# Executar proximo apenas em caso de sucesso
commandA && commandB

# Executar proximo apenas em caso de falha
commandA || commandB

# A em caso de sucesso, B em caso de falha (ramificacao simples)
command && echo "OK" || echo "NG"

# Sair do script se o passo falhar
command || exit 1

# Encerrar um script explicitamente como sucesso / falha
exit 0   # sucesso
exit 1   # falha

Proxima Leitura