if Bedingung auf mehreren Zeilen in der Bash-Shell

18

Ich habe eine Bash-Shell-Funktion, die ein Argument aufnimmt und bei Bedarf etwas darauf ausführt.

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

Ich möchte diese Methode mit mehreren Argumenten aufrufen und prüfen, ob mindestens eines davon erfolgreich war.

Ich habe versucht, etwas wie:

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

Was wird die richtige Syntax dafür sein?
EDIT
Also - Ich möchte sicherstellen, dass auch wenn die erste Bedingung erfüllt ist, alle anderen Bedingungen weiterhin ausgewertet werden.

Vielen Dank,

Itay
quelle
Ich habe meine Antwort aktualisiert.
Tectux
Danke, können Sie bitte ein Beispiel geben?
Itay
Ich habe meiner Antwort ein Codebeispiel hinzugefügt.
Tectux

Antworten:

6

Führen Sie zuerst die Befehle aus und prüfen Sie dann, ob mindestens einer von ihnen erfolgreich war.

#!/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
quelle
2
Dies ist verwirrend, werde ich mich freuen, wenn Sie eine Erklärung liefern könnte, wie bedingte Anweisungen arbeiten in bash ..., liefert 0 bei Erfolg do_something, aber dann aktualisieren wir Erfolg auf 1 ..., if ((success))auswertet , um etwas anderes als if success. Ich bin verwirrt :)
Itay
2
@Itay ((...))ist ein arithmetischer Befehl. Wenn das Ergebnis ungleich Null ist, wird true (0) zurückgegeben. Wenn das Ergebnis innerhalb 0 ist, wird false (1) zurückgegeben. "Erfolg" wird als Variable behandelt, die eine Zahl enthalten soll. Siehe mywiki.wooledge.org/ArithmeticExpression
geirha
Danke, ich denke, dass der Teil, der mich verwirrt hat, ist, dass 0 wahr und 1 falsch ist, normalerweise ist es das Gegenteil :)
Itay
2
@Itay Ja, es kann zunächst verwirrend sein. Bash unterscheidet sich von Mehrzwecksprachen dadurch, dass es "befehlsbasiert" ist. Es ruft keine Funktionen auf, verfügt nicht über Klassen und Methoden, führt Befehle aus und testet den Beendigungsstatus von Befehlen. Und es ist viel einfacher, Befehle in Bash auszuführen als in Sprachen wie C, Python, Java, Perl usw. Befehle werden mit 0 beendet, um den Erfolg zu signalisieren, und 1-255 für verschiedene Arten von Fehlern. (Ein Befehl kann im Allgemeinen nur auf eine Weise erfolgreich sein, aber aus verschiedenen Gründen fehlschlagen.)
geirha
2
Diese Lösung hat den Vorteil, dass Sie die Zeilen auskommentieren können, die Sie nicht vorübergehend deaktivieren möchten
Josiah Yoder
30

Verwenden Sie Backslashes.

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

BEARBEITEN

Außerdem möchte ich sicherstellen, dass alle anderen Bedingungen auch dann ausgewertet werden, wenn die erste Bedingung erfüllt ist.

Das ist in nur einer if-Anweisung nicht möglich. Stattdessen können Sie eine for-Schleife verwenden, die die Argumente durchläuft und separat auswertet. So etwas wie:

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
quelle
danke, habe es versucht - ich bekomme eine Fehlermeldung[: do_something: unary operator expected
Itay
Haben Sie jede Bewertung in ihre eigenen Klammern gesetzt? Also [ expr1 ] || [ expr2 ]statt [ expr1 || expr2 ].
Tectux
ja, ich tat: (...
Itay
Ich vermute, dass dies do_something "arg1"als zwei Argumente interpretiert wird, während der Ausdruck unär sein sollte. Jede Art und Weise der Herstellung do_something "arg1"als ein Argument zu bewerten?
Itay
1
Du hast recht. Dies funktioniert auch: if [ $(do_something "arg1") ].
Tectux
5

Die korrekte Syntax lautet:

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

\ wird verwendet, um der Shell mitzuteilen, dass ein Befehl in der nächsten Zeile fortgesetzt wird.

EDIT : Ich denke das sollte machen was du willst:

#!/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
quelle
Vielen Dank, Ergebnisse mit einem Fehler:[: too many arguments
Itay
@Itay Answer aktualisiert.
Eric Carvalho
Aktualisierung der Frage - dies ist noch nicht die endgültige Antwort :(
Itay