si condición en múltiples líneas en bash shell

19

Tengo una función bash shell que toma un argumento y realiza algo si es necesario.

do_somthing() {
  if [need to do something on $1]
  then
    do it
    return 0
  else
    return 1
  fi
}

Quiero llamar a este método con varios argumentos y verificar si al menos uno de ellos tuvo éxito.

Intenté algo como:

if [ do_something "arg1" ||
     do_something "arg2" ||
     do_something "arg3" ]
then
  echo "OK"
else
  echo "NOT OK"
fi

¿Cuál será la sintaxis correcta para eso?
EDITAR
también: quiero asegurarme de que, incluso si la primera condición es verdadera, todas las demás condiciones se evaluarán.

Gracias,

Itay
fuente
He actualizado mi respuesta.
tectux
Gracias, ¿puedes dar un ejemplo?
Itay
1
He agregado un ejemplo de código a mi respuesta.
tectux

Respuestas:

7

Primero ejecute los comandos, luego verifique si al menos uno de ellos tuvo éxito.

#!/bin/bash

success=0
do_something arg1 && success=1
do_something arg2 && success=1
do_something arg3 && success=1

if ((success)); then
    printf 'Success! At least one of the three commands succeeded\n'
fi
geirha
fuente
3
Esto es confuso, me alegraría si pudiera proporcionar alguna explicación sobre cómo funcionan las declaraciones condicionales en bash ..., do_something devuelve 0 en caso de éxito, pero luego actualizamos el éxito a 1 ..., if ((success))evalúa algo diferente a if success. Estoy confundido :)
Itay
2
@Itay ((...))es un comando aritmético. Si el resultado dentro no es cero, devuelve verdadero (0). Si el resultado dentro es 0, devuelve falso (1). "éxito" se trata como una variable que espera contener un número. Ver mywiki.wooledge.org/ArithmeticExpression
geirha
Gracias, supongo que la parte que me confundió es que 0 es verdadero y 1 es falso, generalmente es lo contrario :)
Itay
2
@Itay Sí, puede ser confuso al principio. Bash difiere de los lenguajes de propósito general en que está "basado en comandos"; no llama a funciones, no tiene clases y métodos, ejecuta comandos y prueba los estados de salida de los comandos. Y es mucho más fácil ejecutar comandos en bash que lenguajes como C, python, java, perl, etc. Los comandos salen con 0 para señalar el éxito y 1-255 para varios tipos de fallas. (Un comando generalmente solo puede tener éxito de una manera, pero falla por varias razones diferentes)
geirha
2
Esta solución tiene la ventaja de que puede comentar las líneas que no desea desactivarlas temporalmente
Josiah Yoder
31

Usa barras invertidas.

if [ $(do_something "arg1") ] || \
   [ $(do_something "arg2") ] || \
   [ $(do_something "arg3") ]
then
  echo "OK"
else
  echo "NOT OK"
fi

EDITAR

Además, quiero asegurarme de que, incluso si la primera condición es verdadera, todas las demás condiciones serán evaluadas.

Eso no es posible en una sola declaración if. En su lugar, puede usar un bucle for que itera sobre los argumentos y los evalúa por separado. Algo como:

do_something() {
  for x in "$@"
  do
    if [need to do something on $x]
    then
      do it
    else
      echo "no action required on $x"
    fi
  done
}
tectux
fuente
gracias, lo intenté - me sale un error[: do_something: unary operator expected
Itay
¿Puso cada evaluación entre sus propios corchetes? Entonces en [ expr1 ] || [ expr2 ]lugar de [ expr1 || expr2 ].
tectux
sí, lo hice: (...
Itay
Mi conjetura es que do_something "arg1"se interpreta como dos argumentos, mientras que la expresión debería ser unaria. ¿Alguna forma de hacer que do_something "arg1"se evalúe como un argumento?
Itay
1
Tienes razón. Esto funciona también: if [ $(do_something "arg1") ].
tectux
5

La sintaxis correcta es:

if  do_something "arg1" || \
    do_something "arg2" || \
    do_something "arg3"
then
  echo "OK"
else
  echo "NOT OK"
fi

\ se usa para indicarle al shell que un comando continúa en la siguiente línea.

EDITAR : Creo que esto debería hacer lo que quieres:

#!/bin/bash

do_something() {
  if [need to do something on $1]
  then
    do it
    echo "OK"
  else
    echo "NOT OK"
  fi
}

do_something "arg1"
do_something "arg2"
do_something "arg3"
Eric Carvalho
fuente
Gracias, resultados con un error:[: too many arguments
Itay
@Itay Respuesta actualizada.
Eric Carvalho
Actualización de la pregunta: esta aún no es la respuesta final :(
Itay
-1

Yo prefiero:

if {
    do_something "arg1" ||
    do_something "arg2" ||
    do_something "arg3"
}; then
    echo "OK"
else
    echo "NOT OK"
fi
Toxiro
fuente
Su secuencia de comandos no funcionará en absoluto: después del primer parámetro de prueba, generaría un \ncarácter, por lo que su ifdeclaración generaría algunos errores y do_somethingno son nombres de comandos, por lo que
habrá
Para mí funciona en zsh y bash, IF do_somethinges una función, por supuesto. do_somethingdebe ser función o comando, ¿qué más debería ser? Además, no veo dónde generaría un \npersonaje, excepto después de hacer eco del resultado y esto se espera ...
Toxiro hace