How can I write a shell script that exits, if one part of it fails? For example, if the following code snippet fails, then the script should exit.
n=0
until [ $n -ge 5 ]
do
gksu *command* && break
n=$[$n+1]
sleep 3
How can I write a shell script that exits, if one part of it fails? For example, if the following code snippet fails, then the script should exit.
n=0
until [ $n -ge 5 ]
do
gksu *command* && break
n=$[$n+1]
sleep 3
One approach would be to add set -e to the beginning of your script. That means (from help set):
-e Exit immediately if a command exits with a non-zero status.
So if any of your commands fail, the script will exit.
Alternatively, you can add explicit exit statements at the possible failure points:
command || exit 1
You can exit a script at any place using the keyword exit. You can also specify an exit code in order to indicate to other programs that or how your script failed, e.g. exit 1 or exit 2 etc. (By convention, exit code 0 is for success and anything greater than 0 signifies failure; however, also by convention, exit codes above 127 are reserved for abnormal termination (e.g. by a signal)).
The generic construction to exit on failure is
if [ failure condition ]; then
exit n
fi
with suitable failure condition and n. But in specific scenarios you may proceed differently. Now for your case I interpret your question that if any of the five invocations of gksu fail, then you mean to exit. One way is to use a function like this
function try_command {
for i in 1 2 3 4 5 ; do
if gksu command ; then
return 0
fi
fi
exit 1
}
and then, invoke the loop by try_command.
There are (more) advanced or sophisticated ways of how to address your question. However, the solution above is more accessible to beginners than, say, Stephane's solution.
attempt=0
until gksu command; do
attempt=$((attempt + 1))
if [ "$attempt" -gt 5 ]; then
exit 1
fi
done
exit exits the script unless it's called in a subshell. If that part of the script is in a subshell, for instance because it's within (...) or $(...) or part of a pipe-line, then it will only exit that subshell.
In that case, if you want the script to exit in addition to the subshell, then you'll need to call exit upon that subshell exiting.
For instance, here with 2 nested levels of subshells:
(
life=hard
output=$(
echo blah
[ "$life" = easy ] || exit 1 # exit subshell
echo blih not run
) || exit # if the subshell exits with a non-zero exit status,
# exit as well with the same exit status
echo not run either
) || exit # if the subshell exits with a non-zero exit status,
# exit as well with the same exit status
It can become trickier if the subshell is part of a pipeline. bash has a special $PIPESTATUS array, similar to zsh's $pipestatus one that can help you here:
{
echo foo
exit 1
echo bar
} | wc -c
subshell_ret=${PIPESTATUS[0]}
if [ "$subshell_ret" -ne 0 ]; then
exit "$subshell_ret"
fi
Trap will perform an action upon receiving a signal.
trap "echo EXIT; exit" 0
trap "echo HUP; exit" 1
trap "echo CTL-C; exit" 2
trap "echo QUIT; exit" 3
trap "echo ERR; exit" ERR
n=0
until [ $n -ge 5 ]
do
n=$[$n+1]
echo $n
sleep 3
done
Run this and let it exit normally. It traps on signal 0.
EXIT
Run it again and interrupt with ^C. It traps on both signal 2 and signal 0.
CTL-C
EXIT
A non-zero exit status will trap on ERR
ERR
EXIT
I prefer doing it this way:
function exit_failed() {
echo ""
echo " ... batch failed !!!"
echo ""
exit 1
}
7z a $FN . || exit_failed
<call-something-else> || exit_failed