Varios operadores lógicos, ((A || B) & & C) y “ error de sintaxis cerca de un token inesperado ”

Estoy trabajando con Bash 3 y estoy intentando formar un condicional. En C / C ++, es absolutamente simple: ((A || B) && C). En Bash, no es así (creo que los autores de Git deben haber contribuido con este código antes de pasar a otros esfuerzos).

Esto no funciona. Tenga en cuenta que <0 or 1> no es una cadena literal; significa 0 o 1 (generalmente proviene 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 

Da como resultado:

line 322: syntax error near unexpected token `[[" 

Luego intenté:

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 en:

line 322: syntax error near unexpected token `[[" 

Parte del problema es que los resultados de búsqueda son ejemplos triviales y no ejemplos más complejos con condicionales compuestos.

¿Cómo realizo un ((A || B) && C) en Bash?


Estoy listo para desenrollarlo y repetir los mismos comandos en varios bloques:

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 

Respuesta

La sintaxis de bash no es similar a C, incluso si una pequeña parte está inspirada en C. No puede simplemente intentar escribir código C y esperar que funcione.

El objetivo principal de un shell es ejecutar comandos. El comando de corchetes abiertos [ es un comando que realiza una única prueba¹. Incluso puede escribirlo como test (sin el corchete de cierre final). Los operadores || y && son operadores de shell, combinan comandos , no pruebas.

Entonces, cuando escribe

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

eso «se analiza como

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

que es lo mismo que

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

¿Observas los corchetes desequilibrados? Sí, eso no es bueno. Su intento con paréntesis tiene el mismo problema: corchetes falsos.

La sintaxis para agrupar los comandos es llaves. La forma en que se analizan las llaves requiere un comando completo antes de ellas, por lo que deberá terminar el comando dentro de las llaves con una nueva línea o punto y coma.

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

Allí «Es una forma alternativa que consiste en utilizar corchetes dobles. A diferencia de los corchetes simples, los corchetes dobles son una sintaxis de shell especial. Delimitan expresiones condicionales . Dentro de los corchetes dobles, puede usar paréntesis y operadores como && y ||. Dado que los corchetes dobles son sintaxis de shell, el shell sabe que cuando estos operadores están entre corchetes, «forman parte de la sintaxis de la expresión condicional, no de la sintaxis de comandos de shell ordinaria».

Si todas sus pruebas son numéricas, existe otra forma, que delimita expresiones artihméticas . Las expresiones aritméticas realizan cálculos de números enteros con una sintaxis muy similar a la de C.

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

Puede encontrar my bash corchete primer útil.

[ se puede usar en sh simple. [[ y (( son específicos de bash (y ksh y zsh).

¹ También puede combinar varias pruebas con operadores booleanos, pero esto es engorroso de usar y tiene trampas sutiles, así que no lo explicaré.

Comentarios

  • Gracias Giles. ¿Esto es válido para Bash 2 a Bash 4? Necesito algo de portabilidad leve, pero Kusalananda mencionó que algunas cosas que no estaba haciendo son portátiles (¿eso implica que lo que estoy haciendo es no portátil?). Aquí, levemente significa Bash 2 a Bash 4.
  • @jww [[ … ]] fue agregado en bash 2.02. ((…)) se agregó en bash 2.0.
  • @Giles – gracias. Bash 2 es probablemente ridículo para la mayoría. Se debe a nuestra gobernanza y nuestra falta de voluntad para abandonar las plataformas más antiguas. Bash 2 y GCC 3 aparecen en nuestras pruebas de Fedora 1. De vez en cuando dejaremos que una plataforma más antigua desaparezca, pero tiene que haber razones para ello. No ‘ t suscríbete a la política de abandono de software de Apple, Microsoft, Mozilla, etc.
  • @jww Por favor, comprenda que la precedencia de || y && cambiar de [ a [[ y ((. Igual precedencia en [ (use paréntesis para controlar el orden de evaluación), pero & & tiene mayor precedencia en [[ y (( que || (como en C).
  • @Roland No, paréntesis dentro de [[ … ]] o $((…)) son solo para agrupar.

Respuesta

Utilice [[:

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

Si prefiere [, lo siguiente funciona:

if [ \( "$A" -eq "0" -o "$B" -ne "0" \) -a "$C" -eq "0" ]; then ... 

Comentarios

  • Gracias, Stephen. En mi caso, usé su primer ejemplo así … regex = ‘ ^ [0-9] + $ ‘ length = $ {#datearg} si! [[$ datearg = ~ $ regex & & $ longitud -eq 8]]; luego echo » error: No es un número de lenth de 8 «; fi

Respuesta

Utilice el operador -o en lugar de su anidado ||. También puede utilizar -a para reemplazar & & si es necesario en sus otras declaraciones. .

 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 

Comentarios

  • Gracias. Me encontré con -a y -o, pero no experimenté con ellos. Alguien en Stack Overflow dijo que lo evitara. En general estuve de acuerdo con ellos, ya que el script es menos legible al usarlos.
  • … pero más portátil.
  • @Kusalananda – Gracias por los avisos sobre la portabilidad. El script debe ejecutarse en sistemas con Bash 2 a Bash 4. ¿Tendrán [[ ( "$A" -eq "0" || "$B" -ne "0" ) && "$C" -eq "0" ]] problemas con ellos?
  • No habrá problemas siempre y cuando se mantenga bash o cualquier otro shell que entienda [[ ... ]].
  • La desventaja de usar -a es que no ‘ t cortocircuito si la primera expresión es falsa. Entonces, si confía en el cortocircuito para evitar que se ejecute una segunda expresión potencialmente fatal, no puede usar -a. Ejemplo: pastebin.com/zM77TXW1

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *