[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Help-bash] Terminate calling bash script upon receiving non zero re
From: |
Greg Wooledge |
Subject: |
Re: [Help-bash] Terminate calling bash script upon receiving non zero return status (and possibly terminate calling script recursively) |
Date: |
Mon, 23 Apr 2012 11:05:06 -0400 |
User-agent: |
Mutt/1.4.2.3i |
On Mon, Apr 23, 2012 at 09:41:05AM -0500, Peng Yu wrote:
> I'm looking for a feature that can terminate the calling bash script
> if the called program return non zero status. But I don't find such a
> feature.
What you want is a magical fairy-tale version of "set -e" which actually
reads your mind and works the way you expect.
As you have concluded, there is no such thing. There is only the real
set -e, which fails half the time and is confusing all of the time.
> I see that && is useful in the following. If prog1 is not returning
> zero, prog2 will not be called.
>
> prog1 && prog2
>
> But this is not convenient if I need to calls many programs.
>
> prog1 && prog2 .... && prog_n
Is every one of them REALLY so critical to your script's execution that
you must abort if any one of them fails? In most scripts there are
only a handful of places that you really need to error check.
#!/bin/bash
# phony example script - rotate a log file
die() { echo "$1" >&2; exit 1; }
cd /my/log/directory || die "couldn't cd to the log directory"
rm -f *.old *.old.gz
mv mylogfile mylogfile.old 2>/dev/null
mydaemon --open-a-new-log-file
chmod 600 mylogfile
nohup gzip -9 mylogfile.old >/dev/null 2>&1 &
In this script, there is only one critical command -- the cd. If that
fails, then our rm would occur in the wrong place... it would be an
absolute disaster. We don't want to do ANYTHING if we can't cd to the
log directory, so we check the cd for errors, and abort.
rm -f doesn't return failure if the file doesn't exist. That's the point
of using the -f flag. If the file's not there, we move on.
I suppressed stderr from the mv because I don't want to hear any moaning
if the current log file (that we're attempting to rotate) doesn't exist.
If it's not there, we simply move on. Yes, I could check for the file
with a test or [[ or [ command, but why bother? If mv does nothing, then
it does nothing.
Then we tell mydaemon to open a new log file. This is daemon-specific.
I also don't care if it fails. It might fail if the daemon's not running,
for example. In that case, some OTHER script will be responsible for
restarting it or notifying someone or whatever. Not my problem. I'm just
rotating a log file, which means I need the daemon to stop writing to it.
If the daemon isn't running, then it's not writing to it -- no problem!
(This is also where a made-up example falls a bit short. Maybe in
real life I'd retry a few times, or notify someone in this script.
Maybe not. There are so many different situations, and there IS NO
GENERAL FORMULA for how to handle them all. Each shell script is unique,
like a snowflake. Or more like a bullet wound. Shell script code is
short, brutal, direct, and dirty. It is not reusable.)
If the chmod fails, that probably means the previous command also failed;
that is, there is no current log file. Here I didn't suppress errors.
If there's no current log file to chmod, then let it notify me. Maybe in
a different log rotate script I'd suppress errors. Or maybe I'd abort if
the daemon kick failed. Or maybe I'd sleep until the file exists, or until
it's been 10 minutes, whichever comes first. Etc.
Then I compress the old log file, in the background, suppressing errors.
If there's no old log file to compress, that error message will be
discarded. Out of sight, out of mind. Since it's a background job, it
will *always* return status 0 (unless I wait for it and retrieve its
actual exit status, but if I were going to do that, I wouldn't run it in
the background in the first place).
So, we have a script with 6 commands in it, and we only error-checked one
of them. Not all 6. And we didn't use set -e to do it.