Save exit code for later
Solution 1
You can wrap the exit
and rm
commands up into a single simple-command with eval
like:
java ... && java ...
eval "rm -f *.class; exit $?"
That way $?
's value when passed to exit
is whatever it gets assigned immediately before eval
runs.
Solution 2
I'd go with:
javac *.java && java -ea Test
test_exit_code=$?
rm -f *.class
exit "$test_exit_code"
Why jump around when exit
is available?
You could use a trap
:
trap 'last_error_code=$?' ERR
For example:
$ trap 'last_error_code=$?' ERR
$ false
$ echo $?
1
$ echo $last_error_code $?
1 0
Solution 3
As far as I know the closest thing bash has to a try...finally
block from a more C-like programming language (which is what you probably would want if it were available) is the trap
construction, which works like this:
trap "rm -f *.class" EXIT
javac *.java && java -ea Test
This will execute "rm -f *.class" when your script exits. If you have something more complex to do, you could put it in a function:
cleanup() {
...
}
trap cleanup EXIT
javac *.java && java -ea Test
If you are so inclined, you can turn this into a fairly general idiom that works roughly like a try...catch...finally
block in C. Something like this:
(
trap "catch_block; exit" ERR
trap finally_block EXIT
# contents of try goes here
)
Note that the parentheses delimit a subshell; with this construction, only the subshell exits if a command fails, not the whole script. Remember that subshells are somewhat computationally expensive so don't use too many (hundreds) of them. Depending on your script you may be able to achieve the same effect more efficiently with shell functions and trap ... RETURN
, but that's up to you to investigate.
Related videos on Youtube
math4tots
Updated on September 18, 2022Comments
-
math4tots almost 2 years
So I have a little script for running some tests.
javac *.java && java -ea Test rm -f *.class
Now the problem with this is that when I run the script
./test
, it will return a success exit code even if the test fails becauserm -f *.class
succeeds.The only way I could think of getting it to do what I want feels ugly to me:
javac *.java && java -ea Test test_exit_code=$? rm -f *.class if [ "$test_exit_code" != 0 ] ; then false; fi
But this seems like something of a common problem -- perform a task, clean up, then return the exit code of the original task.
What is the most idiomatic way of doing this (in bash or just shells in general)?
-
muru over 9 years@math4tots Try the update.
-
math4tots over 9 yearsSo with your update I would have to initialize last_error_code to zero and then return at the end so I would have non-zero exit code if any command threw an error? It is a cool trick, but for my two line hack script, I think I prefer @mikeserv 's answer.
-
mikeserv over 9 years
eval
is always a fan-favorite. -
muru over 9 years@math4tots You can always do
exit ${last_error_code:=0}
. -
muru almost 7 years@avip whatever for? It's already in single quotes, so the variable is only evaluated when the trap is called.
-
avip almost 7 years@muru u r right, my code had double-quoted trap. Thanks.
-
uz7 about 6 yearsIf the code is a function body, you most likely want
return
instead ofexit
.