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
-ae-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ê
bashou 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.