Exit-Code für später speichern

15

Also habe ich ein kleines Skript zum Ausführen einiger Tests.

javac *.java && java -ea Test
rm -f *.class

Das Problem dabei ist, dass beim Ausführen des Skripts ./testein erfolgreicher Beendigungscode zurückgegeben wird, selbst wenn der Test fehlschlägt, weil er rm -f *.classerfolgreich ist.

Die einzige Möglichkeit, die ich mir vorstellen könnte, es dazu zu bringen, das zu tun, was ich will, ist für mich hässlich:

javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
if [ "$test_exit_code" != 0 ] ; then false; fi

Dies scheint jedoch ein häufiges Problem zu sein: Führen Sie eine Aufgabe aus, bereinigen Sie sie und geben Sie den Beendigungscode der ursprünglichen Aufgabe zurück.

Was ist die idiomatischste Art, dies zu tun (in Bash oder nur Muscheln im Allgemeinen)?

math4tots
quelle

Antworten:

5

Sie können die wickeln exitund rmBefehle in einem einzigen einfachen-Befehl oben mit evalwie:

java ... && java ...
eval "rm -f *.class; exit $?"

Dieser Weg $? der Wert, an den übergeben wird, der Wert, exitder unmittelbar vor dem Ausführen zugewiesen wird eval.

mikeserv
quelle
evalist immer ein Fanfavorit.
mikeserv
23

Ich würde gehen mit:

javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
exit "$test_exit_code"

Warum herumspringen, wenn exit verfügbar?


Sie könnten eine verwenden trap :

trap 'last_error_code=$?' ERR

Beispielsweise:

$ trap 'last_error_code=$?' ERR
$ false
$ echo $?
1
$ echo $last_error_code $?
1 0
muru
quelle
Ah, ich stimme zu, es ist besser als mein Original. Es ist jedoch nach wie vor unbefriedigend, dass ich den Exit-Code explizit in einer Variablen speichern muss. Gibt es keine Möglichkeit, einen Exit-Code zu "pushen" und ihn später erneut zu "popen"?
math4tots
@ math4tots Versuchen Sie das Update.
muru
Also müsste ich mit Ihrem Update last_error_code auf Null initialisieren und dann am Ende zurückgeben, damit ich einen Exit-Code ungleich Null hätte, wenn ein Befehl einen Fehler auslöste? Es ist ein cooler Trick, aber für mein zweizeiliges Hack-Skript ziehe ich die Antwort von @mikeserv vor.
math4tots
@ math4tots Das kannst du immer machen exit ${last_error_code:=0}.
muru
@avip für was auch immer? Es steht bereits in einfachen Anführungszeichen, daher wird die Variable nur ausgewertet, wenn die Trap aufgerufen wird.
Muru
9

Soweit ich weiß, ist das, was bash einem try...finallyBlock aus einer C-ähnlichen Programmiersprache am nächsten kommt (was Sie wahrscheinlich wünschen würden, wenn es verfügbar wäre), dastrap Konstruktion, die wie funktioniert:

trap "rm -f *.class" EXIT
javac *.java && java -ea Test

Dies führt "rm -f * .class" aus, wenn Ihr Skript beendet wird. Wenn Sie etwas komplexeres zu tun haben, können Sie es in eine Funktion einfügen:

cleanup() {
    ...
}
trap cleanup EXIT
javac *.java && java -ea Test

Wenn Sie so geneigt sind, können Sie dies in eine ziemlich allgemeine Redewendung umwandeln, die ungefähr wie ein try...catch...finallyBlock in C funktioniert.

(
  trap "catch_block; exit" ERR
  trap finally_block EXIT
  # contents of try goes here
)

Beachten Sie, dass die Klammern eine Unterschale begrenzen. Bei dieser Konstruktion wird nur die Subshell beendet, wenn ein Befehl fehlschlägt, nicht das gesamte Skript. Denken Sie daran, dass Subshells etwas rechenintensiv sind. Verwenden Sie daher nicht zu viele (Hunderte) davon. Abhängig von Ihrem Skript sind Sie möglicherweise in der Lage, denselben Effekt mit Shell-Funktionen und effizienter zu erzielen trap ... RETURN, aber das liegt an Ihnen.

David Z
quelle