Múltiplos operadores lógicos, ((A || B) && C) e “erro de sintaxe próximo ao token inesperado”

8

Estou trabalhando com o Bash 3 e estou tentando formar um condicional. Em C / C ++, seu dead simple: ((A || B) && C) . No Bash, não é assim (acho que os autores do Git devem ter contribuído com este código antes de se mudarem para outros empreendimentos).

Isso não funciona. Observe que <0 or 1> não é um literal de string; isso significa um 0 ou 1 (geralmente vem de grep -i ).

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eqe "0" ]; then ... fi

Isso resulta em:

line 322: syntax error near unexpected token '[['

Eu então tentei:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>
if [ ([ "$A" -eq "0" ]) || ([ "$B" -ne "0" ]) ] && [ "$C" -eq "0" ]; then ... fi

resulta em:

line 322: syntax error near unexpected token '[['

Parte do problema é que os resultados da pesquisa são exemplos triviais, e não os exemplos mais complexos com condicionais compostos.

Como faço para executar um simples ((A || B) && C) no Bash?

Estou pronto para apenas desenrolá-lo e repetir os mesmos comandos em vários blocos:

A=<0 or 1>
B=<0 or 1>
C=<0 or 1>

if [ "$A" -eq "0" ] && [ "$C" -eq "0" ]; then
    ...
elif [ "$B" -ne "0" ] && [ "$C" -eq "0" ]; then
    ... 
fi
    
por jww 16.06.2016 / 14:48

3 respostas

20

A sintaxe do bash não é semelhante ao C, mesmo que uma pequena parte dele seja inspirada por C. Você não pode simplesmente tentar escrever código C e esperar que ele funcione.

O ponto principal de um shell é executar comandos. O comando de suporte aberto [ é um comando, que executa um único teste¹. Você pode até escrever como test (sem o colchete de fechamento final). Os operadores || e && são operadores de shell, eles combinam comandos , não testes.

Então, quando você escreve

[ [ "$A" -eq "0" ] || [ "$B" -ne "0" ] ] && [ "$C" -eq "0" ]

analisado como

[ [ "$A" -eq "0" ] ||
[ "$B" -ne "0" ] ] &&
[ "$C" -eq "0" ]

que é o mesmo que

test [ "$A" -eq "0" ||
test "$B" -ne "0" ] &&
test "$C" -eq "0"

Observe os suportes não balanceados? Sim, isso não é bom. Sua tentativa com parênteses tem o mesmo problema: colchetes espúrios.

A sintaxe para agrupar comandos juntos é chaves. A forma como as chaves são analisadas requer um comando completo antes delas, então você precisará terminar o comando dentro das chaves com uma nova linha ou ponto-e-vírgula.

if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then …

Existe uma maneira alternativa de usar colchetes duplos. Ao contrário dos parênteses únicos, os parênteses duplos são sintaxe especial do shell. Eles delimitam expressões condicionais . Dentro de colchetes duplos, você pode usar parênteses e operadores como && e || . Como os colchetes duplos são a sintaxe do shell, o shell sabe que quando esses operadores estão entre parênteses, eles fazem parte da sintaxe da expressão condicional, e não parte da sintaxe comum do comando shell.

if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then …

Se todos os seus testes forem numéricos, existe ainda outra maneira, que delimita expressões artísticas . Expressões aritméticas executam cálculos inteiros com uma sintaxe muito semelhante a C.

if (((A == 0 || B != 0) && C == 0)); then …

Você pode encontrar o meu primer de colchetes bash útil.

[ pode ser usado em sh simples. [[ e (( são específicos de bash (e ksh e zsh).

¹ Ele também pode combinar vários testes com operadores booleanos, mas isso é complicado de usar e tem armadilhas sutis, então não vou explicá-lo.

    
por 17.06.2016 / 02:05
3

Use o operador -o em vez de seu || aninhado. Você também pode usar -a para substituir & & se necessário em suas outras declarações.

   EXPRESSION1 -a EXPRESSION2
          both EXPRESSION1 and EXPRESSION2 are true

   EXPRESSION1 -o EXPRESSION2
          either EXPRESSION1 or EXPRESSION2 is true


if [  "$A" -eq "0" -o "$B" -ne "0"  ] && [ "$C" -eq "0" ]; then echo success;fi
    
por 16.06.2016 / 15:02
2

Use [[ :

if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...

Se você preferir [ , os seguintes trabalhos:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ...
    
por 16.06.2016 / 14:50