Estou trabalhando com o Bash 3 e estou tentando formar um condicional. Em C / C ++, é muito simples: ((A || B) && C)
. No Bash, não é bem assim (acho que os autores do Git devem ter contribuído com este código antes de seguirem para outros empreendimentos).
Isso não funciona. Observe que <0 or 1>
não é uma string literal; significa 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 `[["
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
resultou em:
line 322: syntax error near unexpected token `[["
Parte do problema é que os resultados da pesquisa são os exemplos triviais, e não os exemplos mais complexos com condicionais compostos.
Como faço um ((A || B) && C)
no Bash?
Estou pronto para simplesmente desenrolar 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
Resposta
A sintaxe do bash não é semelhante a C, mesmo que uma pequena parte dela seja inspirada em C. Você não pode simplesmente tentar escrever código C e esperar que funcione.
O ponto principal de um shell é executar comandos. O comando de colchetes [
é um comando que realiza 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" ]
isso “é 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 colchetes não balanceados? Sim, isso não é bom. Sua tentativa com parênteses tem o mesmo problema: colchetes falsos.
A sintaxe para agrupar comandos são colchetes. A maneira como os colchetes são analisados requer um comando completo antes deles, então você precisará terminar o comando dentro dos colchetes com uma nova linha ou ponto e vírgula.
if { [ "$A" -eq "0" ] || [ "$B" -ne "0" ]; } && [ "$C" -eq "0" ]; then …
Lá É uma forma alternativa de usar colchetes duplos. Ao contrário dos colchetes simples, os colchetes duplos são uma sintaxe especial de 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 uma sintaxe de shell, o shell sabe que, quando esses operadores estão entre colchetes, eles “fazem parte da sintaxe da expressão condicional, não fazem parte da sintaxe de comando do shell comum.
if [[ ($A -eq 0 || $B -ne 0) && $C -eq 0 ]]; then …
Se todos os seus testes forem numéricos, há ainda outra maneira, que delimita expressões arti-méticas . Expressões aritméticas realizam cálculos inteiros com uma sintaxe muito parecida com C.
if (((A == 0 || B != 0) && C == 0)); then …
Você pode encontrar meu colchete bash primer útil.
[
pode ser usado em sh. [[
e ((
são específicos para bash (e ksh e zsh).
¹ Também pode combine vários testes com operadores booleanos, mas isso é complicado de usar e tem armadilhas sutis, então não vou explicar.
Comentários
Resposta
Use [[
:
if [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]; then ...
Se você preferir [
, o seguinte funciona:
if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ...
Comentários
- Obrigado, Stephen. No meu caso, usei seu primeiro exemplo desta forma … regex = ' ^ [0-9] + $ ' length = $ {#datearg} if! [[$ datearg = ~ $ regex & & $ length -eq 8]]; então echo " erro: Não é um número de lenth de 8 "; fi
Resposta
Use o operador -o
em vez do 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
Comentários
- Obrigado. Encontrei
-a
e-o
, mas não experimentei. Alguém no Stack Overflow disse para evitá-lo. Eu concordo principalmente com eles, pois o script é menos legível com eles. - … mas mais portável.
- @Kusalananda – Obrigado pelo aviso sobre portabilidade. O script deve ser executado em sistemas com Bash 2 a Bash 4.
[[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]]
terá problemas com eles? - Não haverá problemas, contanto que você
bash
ou qualquer outro shell que compreenda[[ ... ]]
. - A desvantagem de usar -a é que não ' t curto-circuito se a primeira expressão for falsa. Portanto, se você depende do curto-circuito para evitar a execução de uma segunda expressão potencialmente fatal, não poderá usar -a. Exemplo: pastebin.com/zM77TXW1
[[ … ]]
foi adicionado no bash 2.02.((…))
foi adicionado ao bash 2.0.||
e&&
mude de[
para[[
e((
. Igualdade de precedência em[
(use parênteses para controlar a ordem de avaliação), mas & & tem maior precedência em[[
e((
do que||
(como em C).[[ … ]]
ou$((…))
são apenas para agrupamento.