Reputation: 334
In my bash script, I am trying to have rsync
retry 10 times if it looses connection to its destination before giving up.
I know this code traps all errors but I can live with that for now.
My code is:
lops="0"
while true; do
let "lops++"
rsync $OPT $SRCLINUX $TRG 2>&1 | tee --append ${LOGFILE}
if [ "$?" -eq "0" ]; then
echolog "rsync finished WITHOUT error after $lops times"
break
else
echolog "Re-starting rsync for the ${lops}th time due to ERRORS"
fi
if [[ "$lops" == "10" ]]; then
echolog "GAVE UP DUE TO TOO MANY rsync ERRORS - BACKUP NOT FINISHED"
break
fi
done
It does not work as expected, here is a what happens on the first error:
TDBG6/
rsync: connection unexpectedly closed (131505 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [sender=3.1.1]
rsync finished WITHOUT error after 1 times
Is this because the $? contains the return value of tee
, NOT rsync
?
How can I fix this? (I am personally Linux syntax limited :)
Upvotes: 2
Views: 106
Reputation: 14510
In addition to the other suggestions for working around the pipe confounding your exit code, you can avoid the pipe by using process substitution like so:
rsync "$OPT" "$SRCLINUX" "$TRG" &> >( tee --append "${LOGFILE}" )
which will redirect both stdout
and stderr
(that's the &>
part) into a "file" that is connected to stdin
of the process within the >(...)
, in this case the tee
command you want. So it's very much like the pipe, but without the pipe (the pipe connects stdout
of the left to stdin
of the right behind the scenes, we've just pushed it out in the open here).
Upvotes: 2
Reputation: 46853
I see at least 2 possibilities to fix your problem:
use PIPESTATUS
:
An array variable containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command).
Use it as:
rsync $OPT $SRCLINUX $TRG 2>&1 | tee --append ${LOGFILE}
if (( PIPESTATUS[0] == 0 )); then
use rsync
's --log-file
option.
Notes:
let
and use ((...))
for arithmetic.Upvotes: 3
Reputation: 39030
I believe that the status is the status of the last command in the pipeline.
I don't know how to deal with this in general, but for this specific case you can just redirect the output of the whole loop:
while true; do
...
done | tee -a "$LOGFILE"
Depending on what it's for, this may also mean you don't need the "echolog" function.
Upvotes: 1