Operadores lógicos são fundamentais em shell script para tomar decisões baseadas no status de saída de comandos. Eles permitem executar comandos condicionalmente, de forma concisa e sem a necessidade de estruturas if explícitas. Nesta aula, exploraremos os operadores &&, || e !, além do conceito de curto-circuito e técnicas de encadeamento.

No Bash, cada comando retorna um código de saída (exit code): 0 indica sucesso, e qualquer valor diferente de zero indica falha. Os operadores lógicos utilizam esses códigos para decidir se o próximo comando será executado. Dominar esses operadores torna seus scripts mais enxutos e legíveis.

&& e ||

O operador && (AND lógico) executa o comando à sua direita apenas se o comando à esquerda retornar sucesso (código 0). Já o operador || (OR lógico) executa o comando à direita apenas se o comando à esquerda falhar (código diferente de 0).

Exemplo prático: criar um diretório e, se bem-sucedido, entrar nele.

mkdir meu_diretorio && cd meu_diretorio

Se o mkdir falhar (diretório já existe, permissão negada, etc.), o cd não será executado, evitando erros. Com o ||, podemos executar uma ação alternativa em caso de falha:

mkdir meu_diretorio || echo "Falha ao criar diretório"

É comum combinar && e || para criar um if-else de uma linha:

comando && echo "Sucesso" || echo "Falha"

Atenção: essa construção pode ter efeitos colaterais se o comando do meio falhar, pois o || será acionado. Para maior segurança, prefira if explícito em scripts complexos.

! (negação)

O operador ! inverte o código de saída de um comando: se o comando retorna 0 (sucesso), o ! faz com que o resultado seja 1 (falha) e vice-versa. É útil para executar um bloco apenas quando um comando falha, sem usar o ||.

! comando && echo "Comando falhou"

Exemplo: verificar se um arquivo não existe antes de criar.

! test -f arquivo.txt && touch arquivo.txt

O test -f retorna 0 se o arquivo existe. Com !, invertemos: se não existir (retorno 0 invertido para 1), o touch não executa? Na verdade, o ! nega o código, então se o arquivo não existe, test retorna 1 (falha), ! inverte para 0 (sucesso), e então o && executa o touch. Cuidado com a lógica: ! comando && proximo_comando executa proximo_comando se comando falhar (já que ! torna sucesso).

Curto-circuito

Os operadores && e || utilizam avaliação de curto-circuito: a expressão é avaliada da esquerda para a direita e a execução para assim que o resultado é determinado. Para &&, se o primeiro comando falha, o resultado já é falso, então o segundo não é executado. Para ||, se o primeiro comando tem sucesso, o resultado já é verdadeiro, então o segundo é ignorado.

Isso é útil para evitar comandos desnecessários ou perigosos. Por exemplo, verificar se um diretório existe antes de tentar acessá-lo:

[ -d /caminho ] && cd /caminho

Se o diretório não existir, o cd não é executado, evitando erro. O curto-circuito também permite encadear várias condições de forma eficiente.

Encadeamento de comandos

Encadeamento é o uso de operadores lógicos para executar múltiplos comandos em sequência, com controle de fluxo. É possível combinar && e || para criar pipelines condicionais complexos.

Exemplo: tentar criar um diretório, se falhar, tentar outro nome, e se tudo falhar, exibir erro.

mkdir dir1 || mkdir dir2 || echo "Não foi possível criar diretório"

Outro exemplo: verificar se um arquivo pode ser lido e, se sim, exibir seu conteúdo; caso contrário, exibir erro.

[ -r arquivo.txt ] && cat arquivo.txt || echo "Arquivo não legível"

O encadeamento pode incluir subcomandos com () para agrupar lógica:

(comando1 && comando2) || (comando3 && comando4)

Isso permite construir árvores de decisão sem usar if explícito, mas cuidado com a legibilidade: para scripts longos, prefira estruturas condicionais tradicionais.

Boas práticas e observações finais

Embora os operadores lógicos sejam poderosos, evite usá-los em excesso para não prejudicar a legibilidade. Para scripts simples, eles são ótimos; para lógicas complexas, use if/then/else. Lembre-se de que o código de saída do último comando executado determina o resultado geral da expressão. Teste sempre seus scripts com diferentes cenários (sucesso e falha) para garantir o comportamento esperado.

Referências

Exercícios

  1. Escreva um comando que crie um arquivo chamado "teste.txt" e, se bem-sucedido, escreva "Criado com sucesso" no terminal. Se falhar, escreva "Falha ao criar".

    ✓ Resposta:
    touch teste.txt && echo "Criado com sucesso" || echo "Falha ao criar"
  2. Usando o operador !, escreva um comando que execute "echo 'Arquivo não existe'" apenas se o arquivo "dados.txt" não existir.

    ✓ Resposta:
    ! test -f dados.txt && echo "Arquivo não existe"
  3. Explique o que acontece na execução de: false && echo "sim" || echo "não". Justifique com o conceito de curto-circuito.

    ✓ Resposta: O comando false retorna 1 (falha). O && avalia: como false falhou, o curto-circuito impede a execução de "echo sim". O resultado do && é falso (código 1). Então o || é avaliado: como o comando anterior falhou, o || executa "echo não". Portanto, a saída será "não".
  4. Escreva um encadeamento que tente remover o arquivo "temp.txt" com rm. Se falhar (arquivo não existe), tente usar o comando rm -f (força remoção). Se ainda falhar, exiba "Não foi possível remover".

    ✓ Resposta:
    rm temp.txt || rm -f temp.txt || echo "Não foi possível remover"
  5. Usando apenas operadores lógicos (&&, ||, !), escreva um comando que execute "echo 'Sucesso'" se o diretório "/tmp" existir e for gravável; caso contrário, execute "echo 'Falha'". Dica: use test -d e test -w.

    ✓ Resposta:
    test -d /tmp && test -w /tmp && echo "Sucesso" || echo "Falha"