¿Cuál es la sintaxis de una condición compleja en shell?

10

Si desea expresar la siguiente prueba en shell (sh):

if ( a == 1 && ( b == 1 || b == 2 )) { ... }

Hasta ahora, lo mejor que he podido escribir es esto:

if [[ $a -eq 1 ]]; then
  if [[ $b -eq 1 || $b -eq 2 ]]; then
     ...
  fi
fi

No sé cómo componer && y || con precedencia correcta Buscar en Google no me ha dado ninguna respuesta (los tutoriales solo dan ejemplos básicos, si los hay)

¿Cuál es la sintaxis para combinar esos dos si en uno?

Offirmo
fuente
1
¿Alguna razón para no usar ksh? Entonces su código inicial requeriría solo un par de paréntesis más:if (( a == 1 && ( b == 1 || b == 2 ))); then :; fi
manatwork

Respuestas:

14

Tenga en cuenta que [[ ]]no está ni en Bourne ni en POSIX sh. Para una shsintaxis verdadera , hay varias formas de hacerlo.

Usando solo un [ ]par

if [ 1 -eq "$a" -a \( 1 -eq "$b" -o 2 -eq "$b" \) ]; then
    # ...
fi

o Evitar el POSIX -ay las -oopciones 1

if [ 1 -eq "$a" ] && { [ 1 -eq "$b" ] || [ 2 -eq "$b" ]; }; then
    # ...
fi

1 Una razón para evitar -ay -oes la máxima portabilidad: no todas testo las [implementaciones pueden manejar más de 4 argumentos, que es precisamente lo que obtienes si encadenas expresiones con -ay -oy \( \).

jw013
fuente
Mis guiones tienen el #! / bin / sh shebang, y el shell predeterminado es ksh . ¿Por qué no se usaría sh?
Offirmo
2
@Offirmo Si declara su secuencia de comandos como /bin/sh, es incorrecto escribir la secuencia de comandos utilizando características que no están en sh. Debes saber que kshNO es sh, sino un superconjunto de sh. Si lleva su script ksh-but-declarado-como- sha un sistema donde shno hay un enlace simbólico ksh, puede romperse. Puede evitar ese problema asegurándose de que su script coincida con la declaración.
jw013
Pensé que establecer / bin / sh como shebang haría que mis scripts se invoquen a través de / bin / sh . ¿Quiere decir que mi shell predeterminado (ksh) ignora el shebang y lo interpreta directamente?
Offirmo
@Offirmo Tienes razón: /bin/shse invocará un shebang de /bin/sh. El problema es /bin/shno acepta [[. No puede usar [[o usar un shell que acepte [[, por ejemplo ksh, como su shebang.
jw013
2
El problema no es que mucho de lo que -a/ -ono son admitidos por algunas implementaciones, pero que no es confiable para los argumentos arbitrarios. Like [ "$a" = "$b" -o "$b" = "$c" ]fallaría para valores de $alike !con muchas [implementaciones.
Stéphane Chazelas
2

Probé un poco de sintaxis y descubrí que

if [[ $a -eq 1 ]] && [[ $b -eq 1 || $b -eq 2 ]]; then
 ...
fi

está trabajando.

Offirmo
fuente
1
esto funciona para la versión bash anterior 4.
Nikhil Mulley
2

Otro enfoque POSIX:

if [ "$((a == 1 && ( b == 1 || b == 2 )))" -ne 0 ]; then
  ...
fi
Stéphane Chazelas
fuente
0

La forma correcta de hacerlo con un mero shell:

if test 1 -eq "$a" && test 1 -eq "$b" -o 2 -eq "$b"; then 
    ...
fi

Explicación:

testaquí sirve como paréntesis y -ocomo lógico o. Si fuera lógico y dentro del "paréntesis" lo usaría -a.

Más sobre eso se puede encontrar aquí

Omer Dagan
fuente