Salva il codice di uscita per dopo


15

Quindi ho una piccola sceneggiatura per l'esecuzione di alcuni test.

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

Ora il problema è che quando eseguo lo script ./test, verrà restituito un codice di uscita riuscito anche se il test fallisce perché ha esito rm -f *.classpositivo.

L'unico modo in cui potrei pensare di farlo fare ciò che voglio è brutto per me:

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

Ma questo sembra essere un problema comune: eseguire un'attività, ripulire, quindi restituire il codice di uscita dell'attività originale.

Qual è il modo più idiomatico di farlo (in bash o solo conchiglie in generale)?

Risposte:


5

Puoi racchiudere i comandi exite rmin un singolo comando semplice con evallike:

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

In questo modo $?il valore quando viene passato exitè qualunque cosa venga assegnata immediatamente prima evaldell'esecuzione.


evalè sempre il preferito dai fan.
Mikeserv,

23

Vorrei andare con:

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

Perché saltare quando exitè disponibile?


Puoi usare un trap:

trap 'last_error_code=$?' ERR

Per esempio:

$ trap 'last_error_code=$?' ERR
$ false
$ echo $?
1
$ echo $last_error_code $?
1 0

Ah, sono d'accordo che è meglio del mio originale. Ma mi sembra ancora insoddisfacente che devo memorizzare esplicitamente il codice di uscita in una variabile. Non c'è modo di "spingere" un codice di uscita e "pop" di nuovo in un secondo momento?
math4tots,

@ math4tots Prova l'aggiornamento.
Muru,

Quindi con il tuo aggiornamento dovrei inizializzare last_error_code a zero e poi tornare alla fine in modo da avere un codice di uscita diverso da zero se qualche comando generasse un errore? È un bel trucco, ma per il mio script hack su due righe, penso di preferire la risposta di @mikeserv.
math4tots

@ math4tots Puoi sempre fare exit ${last_error_code:=0}.
Muru,

@avip qualunque cosa per? È già tra virgolette singole, quindi la variabile viene valutata solo quando viene chiamata la trap.
Muru,

9

Per quanto ne so la cosa più vicina che bash ha a un try...finallyblocco da un linguaggio di programmazione più simile a C (che è quello che probabilmente vorresti fosse se fosse disponibile) è la trapcostruzione, che funziona in questo modo:

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

Questo eseguirà "rm -f * .class" alla chiusura dello script. Se hai qualcosa di più complesso da fare, potresti metterlo in una funzione:

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

Se sei così incline, puoi trasformarlo in un linguaggio abbastanza generale che funziona all'incirca come un try...catch...finallyblocco in C. Qualcosa del genere:

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

Si noti che le parentesi delimitano una subshell; con questa costruzione, solo la subshell esce se un comando fallisce, non l'intero script. Ricorda che i subshells sono in qualche modo costosi dal punto di vista computazionale, quindi non usarne troppi (centinaia). A seconda del tuo script potresti essere in grado di ottenere lo stesso effetto in modo più efficiente con le funzioni della shell e trap ... RETURN, ma spetta a te investigare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.