Guardar código de salida para más tarde

15

Así que tengo un pequeño script para ejecutar algunas pruebas.

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

Ahora el problema con esto es que cuando ejecuto el script ./test, devolverá un código de salida exitoso incluso si la prueba falla porque rm -f *.classtiene éxito.

La única forma en que puedo pensar en hacer que haga lo que quiero me parece fea:

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

Pero esto parece un problema común: realice una tarea, limpie y luego devuelva el código de salida de la tarea original.

¿Cuál es la forma más idiomática de hacer esto (en bash o simplemente conchas en general)?

math4tots
fuente

Respuestas:

5

Puede envolver los comandos exity rmen un solo comando simple con evallike:

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

$?El valor de esa forma cuando se pasa exites lo que se le asigna inmediatamente antes de evalejecutarse.

mikeserv
fuente
evalSiempre es un favorito de los fanáticos.
mikeserv
23

Yo iría con:

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

¿Por qué saltar cuando exitestá disponible?


Podrías usar un trap:

trap 'last_error_code=$?' ERR

Por ejemplo:

$ trap 'last_error_code=$?' ERR
$ false
$ echo $?
1
$ echo $last_error_code $?
1 0
muru
fuente
Ah, estoy de acuerdo, es mejor que mi original. Pero todavía me parece insatisfactorio que tenga que almacenar explícitamente el código de salida en una variable. ¿No hay forma de 'empujar' un código de salida y 'pop' de nuevo más tarde?
math4tots
@ math4tots Pruebe la actualización.
muru
Entonces, con su actualización, ¿tendría que inicializar last_error_code a cero y luego regresar al final para tener un código de salida distinto de cero si algún comando arrojara un error? Es un truco genial, pero para mi script de pirateo de dos líneas, creo que prefiero la respuesta de @mikeserv.
math4tots
@ math4tots Siempre puedes hacerlo exit ${last_error_code:=0}.
muru
@avip para lo que sea? Ya está entre comillas simples, por lo que la variable solo se evalúa cuando se llama a la trampa.
muru
9

Hasta donde sé, lo más cercano que bash tiene a un try...finallybloque de un lenguaje de programación más parecido a C (que es lo que probablemente desearía si estuviera disponible) es la trapconstrucción, que funciona así:

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

Esto ejecutará "rm -f * .class" cuando salga el script. Si tiene algo más complejo que hacer, puede ponerlo en una función:

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

Si está tan inclinado, puede convertir esto en un lenguaje bastante general que funciona más o menos como un try...catch...finallybloque en C. Algo así:

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

Tenga en cuenta que los paréntesis delimitan una subshell; Con esta construcción, solo la subshell sale si falla un comando, no todo el script. Recuerde que las subcapas son algo computacionalmente caras, así que no use demasiadas (cientos) de ellas. Dependiendo de su script, puede lograr el mismo efecto de manera más eficiente con las funciones de shell y trap ... RETURN, pero eso depende de usted para investigar.

David Z
fuente