I am a noob in shell-scripting. I want to print a message and exit my script if a command fails. I've tried:
my_command && (echo 'my_command failed; exit)
but it does not work. It keeps executing the instructions following this line in the script. I'm using Ubuntu and bash.
Try:
my_command || { echo 'my_command failed' ; exit 1; }
Four changes:
- Change
&&
to||
- Use
{ }
in place of( )
- Introduce
;
afterexit
and - spaces after
{
and before}
Since you want to print the message and exit only when the command fails ( exits with non-zero value) you need a ||
not an &&
.
cmd1 && cmd2
will run cmd2
when cmd1
succeeds(exit value 0
). Where as
cmd1 || cmd2
will run cmd2
when cmd1
fails(exit value non-zero).
Using ( )
makes the command inside them run in a sub-shell and calling a exit
from there causes you to exit the sub-shell and not your original shell, hence execution continues in your original shell.
To overcome this use { }
The last two changes are required by bash.
The other answers have covered the direct question well, but you may also be interested in using set -e
. With that, any command that fails (outside of specific contexts like if
tests) will cause the script to abort. For certain scripts, it's very useful.
Note also, each command's exit status is stored in the shell variable $?, which you can check immediately after running the command. A non-zero status indicates failure:
my_command
if [ $? -eq 0 ]
then
echo "it worked"
else
echo "it failed"
fi
If you want that behavior for all commands in your script, just add
set -e
set -o pipefail
at the beginning of the script. This pair of options tell the bash interpreter to exit whenever a command returns with a non-zero exit code.
This does not allow you to print an exit message, though.
I've hacked up the following idiom:
echo "Generating from IDL..."
idlj -fclient -td java/src echo.idl
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi
echo "Compiling classes..."
javac *java
if [ $? -ne 0 ]; then { echo "Failed, aborting." ; exit 1; } fi
echo "Done."
Precede each command with an informative echo, and follow each command with that sameif [ $? -ne 0 ];...
line. (Of course, you can edit that error message if you want to.)
Provided my_command
is canonically designed, ie returns 0 when succeeds, then &&
is exactly the opposite of what you want. You want ||
.
Also note that (
does not seem right to me in bash, but I cannot try from where I am. Tell me.
my_command || {
echo 'my_command failed' ;
exit 1;
}
You can also use, if you want to preserve exit error status, and have a readable file with one command per line:
my_command1 || exit $?
my_command2 || exit $?
This, however will not print any additional error message. But in some cases, the error will be printed by the failed command anyway.
The trap
shell builtin allows catching signals, and other useful conditions, including failed command execution (i.e., a non-zero return status). So if you don't want to explicitly test return status of every single command you can say trap "your shell code" ERR
and the shell code will be executed any time a command returns a non-zero status. For example:
trap "echo script failed; exit 1" ERR
Note that as with other cases of catching failed commands, pipelines need special treatment; the above won't catch false | true
.
The following functions only echoes errors if a command fails:
silently () {
label="${1}"
command="${2}"
error=$(eval "${command}" 2>&1 >"/dev/null")
if [ ${?} -ne 0 ]; then
echo "${label}: ${error}" >&2
exit 1
fi
}
来源:https://stackoverflow.com/questions/3822621/how-to-exit-if-a-command-failed