Dúvida sobre Bash, operadores && e ||

Boa noite. Os operadores && e || estão me incomodando :thinking:, não entendi, afinal eles são operadores lógicos como em C e C++ ou são operadores condicionais que servem para fazer algo quando o retorno do comando for 0 ou diferente de 0? Realmente é bem confuso, pois várias pessoas dizem coisas diferentes.

1 curtida

Boa noite! Os operadores && e || são operadores lógicos em várias linguagens de programação, incluindo C e C++. Eles são usados para avaliar expressões condicionais e tomar decisões com base no resultado dessas expressões.

  • O operador && (E lógico) retorna verdadeiro (1) se ambos os operandos forem verdadeiros (diferentes de zero). Caso contrário, retorna falso (0).
  • O operador || (OU lógico) retorna verdadeiro (1) se pelo menos um dos operandos for verdadeiro (diferente de zero). Retorna falso (0) apenas se ambos os operandos forem falsos.

Eles não são operadores condicionais no sentido de realizar ações com base no valor retornado. Eles são operadores de controle de fluxo que ajudam a determinar se um bloco de código deve ser executado com base nas condições lógicas.

Por exemplo, em C ou C++, você pode usá-los em estruturas condicionais como o if, while, for, etc., para controlar o fluxo do programa. Aqui está um exemplo em C++:

int a = 5;
int b = 10;

if (a > 0 && b > 0) {
    // Este bloco de código será executado se ambas as condições forem verdadeiras.
    cout << "Ambas as condições são verdadeiras." << endl;
}

if (a < 0 || b < 0) {
    // Este bloco de código será executado se pelo menos uma das condições for verdadeira.
    cout << "Pelo menos uma das condições é verdadeira." << endl;
}

Portanto, eles são operadores lógicos e não operadores condicionais para executar ações com base no retorno de uma função. Eles são usados para criar condições lógicas e tomar decisões em seu código com base nessas condições.

4 curtidas

No bash && e || são considerados ambos, pois por exemplo, podemos ter tanto:

existe=true
legivel=true

if $existe && $legivel; then
    echo "existe e é legível."
else
    echo "não existe e/ou não é legível."
fi

como :

echo 1 && echo 0 && echo 1
3 curtidas

Boa noite. Aproveitando esse tópico para não ter que criar outro, qual a diferença do [ ] para o [[ ]]. Também ajudaria bastante se citasse exemplos. :raised_hand_with_fingers_splayed:

o primeiro trata seus argumentos como string(texto), o segundo como expressões do shell, como você pode perceber, o segundo é mais poderoso.

Como você pode ver, contexto é tudo em Bash, te aconselho a dar uma boa focada nessa questão do contexto, pois Bash não tem tipos fortemente definidos, depende do contexto.

Por exemplo:

x="Hello"  # x é texto
y=42       # y é texto
...
a=5 # texto...
b=3 # texto...
c=$((a + b)) # trata a e b como inteiros
...
d=casa # texto...
e=$((d + 1))  # trata d como 0.
``
4 curtidas

Acrescentando exemplos:

if [ $idade -eq 18 ]; then
  echo "Você tem 18 anos."
fi

if [[ $nome == "João" && $idade -ge 18 ]]; then
  echo "Você é o João e tem 18 anos ou mais."
fi
1 curtida

Obrigado pelas respostas @romulopb e @leoberbert.

Corrijam-me se eu estiver errado!

Pois irei criar um markdown para anotações sobre semelhanças e diferenças.

O padrão POSIX (Portable Operating System Interface) para shells, não suporta operadores lógicos como && e || dentro dos colchetes simples [ ] e nem operadores de comparação numérica, como >, <, <=, e >=, onde também não são suportados nos colchetes simples [ ], certo?.
Já o Bash suporta comparações mais avançadas usando os duplos colchetes [[ ]] com os operadores acima, correto?

Fonte: Chatgpt

Está correto, mas não esqueça o que mencionei:

coloquei essa questão pois é o diferencial mais sutil dos 2, por exemplo, isso vai dar erro:

var="a b"
if [ $var = "a b" ]; then
   echo ab
fi

Isso não:

var="a b"
if [[ $var = "a b" ]]; then
   echo ab
fi

porem note que estes também funcionam:

var="ab"
if [ $var = "ab" ]; then
   echo ab
fi
var="a b"
if [ "$var" = "a b" ]; then
   echo ab
fi

de uma procurada sobre texto ou palavra/word (envolve divisão de palavra, expansão de coringa/globbing e afins, etc) vs texto literal vs expressão de shell (comportamento peculiar).

Eu sei que você deve estar pensando “que coisa confusa” :sweat_smile: eu te entendo… Mas “ha método na loucura”.

2 curtidas

Rapaz, shellscript é muito difícil, ou eu que sou lento mesmo :P, pelo menos para entender como funciona e etc. Valeu pelo help :slight_smile:

Eu acho mais adequado conceituá-los como operadores estritamente condicionais, decidindo se o comando a seguir vai rodar dependendo do resultado do comando anterior.

Mesmo no exemplo do @romulopb, o que acontece é que existem comandos chamados true (que sempre retorna 0) e false (que sempre retorna 1); não são “valores especiais” como nas demais linguagens de programação. Se você colocasse 1 nas variáveis existe e legivel, o que você receberia um erro bash: 1: comando não encontrado e contaria como falso para &&/||.

A diferença fundamental é que [ ] é um comando qualquer (mais precisamente, um “syntactical sugar” para o comando test), enquanto [[ ]] é de fato uma sintaxe especial.

A principal consequência é que com [, você idealmente coloca aspas em todas as variáveis que você utilizar, para evitar um dos fenômenos do shell, o “word-splitting” (dividir uma string nos espaços).

Em um exemplo de outra resposta:

var='a b'
[ $var = 'a b' ] && echo legal

O que acontece é que $var é dividido nos espaços antes de ser inserido no comando, e acaba que o [ enxerga é:

[ a b = 'a b' ]

O que esse b tá fazendo à solta aqui?

Agora com aspas

var='a b'
[ "$var" = 'a b' ] && echo legal
# ou test "$var" = 'a b' && echo legal

As aspas impedem a divisão nos espaços, e o comando final é coerente: [ 'a b' = 'a b' ].

Considere mais esse exemplo de outra resposta:

nome='João'
idade=18
[[ $nome = "João" && $idade -ge 18 ]]

Caso você tentasse fazer isso com [, você teria:
[ $nome = "João" && $idade -ge 18 ]

Apesar dos conteúdos de nome e idade não terem espaços, lembre-se que [ é um comando qualquer na fila do pão. O shell vai priorizar o processamento do && no meio e rachá-lo em dois comandos:

# antes do &&
[ $nome = "João"
# depois do &&
$idade -ge 18 ]

O primeiro [ vai reclamar que falta um ] e o segundo comando nem vai ser executado (e se fosse, daria em 18: comando não encontrado, já que $idade seria considerado o comando).

O certo seria:
[ "$nome" = "João" ] && [ "$idade" -ge 18 ]
ou
test "$nome" = "João" && test "$idade" -ge 18

No [[ ]], como ele é uma sintaxe especial, ele pode se dar ao luxo de alterar o comportamento do shell e desativar o wordsplitting e se responsabilizar pelo processamento de && e || no seu “domínio”. Como ele é mais fácil de entender para quem vem de outras linguagens de programação, você vai encontrar gente que faz questão de não usar o [.

Só uma correção, < e > dentro de [[ ]] não são operações numéricas, são operações lexicográficas (comparando ordem alfabética). Por exemplo, [[ 10 < 2 ]] seria verdadeiro (pois 1 vem antes de 2 na ordem alfabética). Se quiser comparações nuḿericas, use (( )) (ex: ((10 < 2)).

Shell script é realmente uma linguagem caótica, surgiu no decorrer de décadas com vários autores (Thompson, Bourne, Almquist, Korn…) cada um aumentando um ponto enquanto tentavam manter compatibilidade com o que vinha antes, muitas vezes tendo que manter comportamentos obsoletos (o próprio wordsplitting é um exemplo) e fazer recursos novos só valerem dentro de certos contextos para não quebrar scripts antigos.

2 curtidas

Realmente você tem razão, neste caso ainda temos comandos sendo avaliados e seria correto dizer que && está agindo como operador condicional, mas e nos caso, tais como você apresentou:

if [[ $nome = "João" && $idade -ge 18 ]]; ...

Acredito que aqui && não esteja avaliando 2 comandos.

1 curtida

Realmente, há somente lógica entre expressões.

Isso que dá focar como na laser na especificação POSIX, onde são descritos como operadores de controle.

1 curtida

Bom se tem uma linguagem que pode dar confusão é essa. :sweat_smile:

Eu assino embaixo… Programação tem dessas, até mesmo em C/C++ fica a questão, pois querendo ou não:

if(func1() && func2()) ...

Temos um comportamento de short-circuit que é comportamento de operador condicional

2 curtidas

Cheguei atrasado mas os amigos já representaram tudo :slight_smile:

1 curtida

O que eu fiz e faço,eu recomendo sempre, faça um clone do Linux no Github, direto do perfil do Linux Torvalds, para você analisar o Kernel do sistema,e no referente ao assunto o tópico, analisar os códigos Shell script que são conjunção com o python no sistema Linux. Assim você poderá entender pelo código o que o autor disse no projeto Linux. Eu estou desenvolvendo minha versão do sistema Linux baseado em archlinux, tive de estudar dessa forma, pois este é o meu foco,um objetivo pronto,um modelo, trabalho com uma equipe de quatro pessoas,dois irmãos e duas irmãs. É o mesmo esquema no aprendizado de HTML CSS e Javascript,para entender estas linguagens, sempre se baseamos em modelos prontos,para entendimento do que queremos replicar com nossa encorporamento mediante os modelos exemplos. No C,C++, Shell script e python,eu recomendo o mesmo, procure exemplo de modelo já pronto,no caso projetos para você entender com funciona e alcançar a fluência. Quando terminar-mos minha versão do sistema Archlinux,eu subirei a versão na minha conta no Github, também aqui no Dplus com a galera,no caso,o link do projeto via minha conta Github. Gostei do seu tópico,e das outras abordagens dos outros usuários. Quer entender uma linguagem? Estude modelos prontos como exemplo.:coffee::crossed_fingers::bulb: