Reputation: 170440
I am looking for a nice and clean method for implementing a retry loop-mechanics in bash.
Here is how is supposed to work:
retries = 3
while retries:
cmd1
cmd2
cmd3
if not_error:
break
echo "something went wrong, let's wait 60 seconds and retry"
sleep 60
retries --
if retries = 0:
exit "Failed!"
Each of the commands can fail and I would prefer to stop running the next commands and just do to the retry code.
Upvotes: 7
Views: 10496
Reputation: 1763
My solution is to use for loop, bash and Here document.
#!/bin/bash
set -e
for count in $(seq 1 5); do bash <<EOF && break
echo "try $count ..."
false
EOF
done && echo ok || echo err
It's easy to use the same method to run command remotely or inside container, for example,
#!/bin/bash
set -e
for count in $(seq 1 5); do ssh remote-host bash <<EOF && break
echo "try $count ..."
false
EOF
done && echo ok || echo err
Upvotes: 0
Reputation: 1
This is what worked when using a plain /bin/sh
shell (where bash is not available):
retries=3
while [[ $retries -gt 0 ]]; do
if cmd1 && cmd2 && cmd3; then
echo "Passed!"
exit 0
else
echo "something went wrong, let's wait 2 seconds and retry"
sleep 2
retries=$((retries - 1))
fi
done
echo "Failed!"
exit 1
Upvotes: 0
Reputation: 785128
Something like this:
#!/bin/bash
retries=3
for ((i=0; i<retries; i++)); do
cmd1 && cmd2 && cmd3
[[ $? -eq 0 ]] && break
echo "something went wrong, let's wait 60 seconds and retry"
sleep 60
done
(( retries == i )) && { echo 'Failed!'; exit 1; }
exit 0
Upvotes: 5
Reputation: 859
This is behavior that is worth externalizing and reusing:
See: https://github.com/kadwanev/retry
retry -t 3 pipeline.sh
if [ $? -ne 0 ]; then
echo "Failed"
exit 1
fi
This will retry up to 3 times and then return if every attempt failed.
Upvotes: 2
Reputation: 6960
You can try this solution:
retries=3
while [ retries gt 0 ]; do
if cmd1 && cmd2 && cmd3; then
echo "Passed!"
exit 0
else
echo "something went wrong, let's wait 60 seconds and retry"
sleep 60
((retries --))
fi
done
echo "Failed!"
exit 1
Upvotes: 0
Reputation: 589
Over the years I have come with the following "core" loop for such situations:
(r=3;while ! some_cmd ; do ((--r))||exit;sleep 60;done)
This has the benefit that the logic is self-contained into a single statement, and the expression will evaluate to true if the command succeeded, or false if it did not after 3 attempts. This is quite useful if you're running with set -e
, or to replace an existing simple command with multiple retries of that command.
In your case this could translate to:
if ! (r=3; while ! { cmd1 && cmd2 && cm3 ; } ; do
((--r)||exit
echo "something went wrong, let's wait 60 seconds and retry"
sleep 60;done) ; then
echo "Failed!"
exit 1
fi
echo "Passed!"
exit 0
Upvotes: 14
Reputation: 531125
This may not be the cleanest if the individual commands are long:
retries=3
while ((retries > 0)); do
cmd1 &&
cmd2 &&
cmd3 && break
echo "something went wrong, let's wait 60 seconds and retry"
sleep 60
((retries --))
done
if ((retries == 0 )); then
echo "Failed!"
exit 1
fi
The &&
operator runs the command on its right if the command on its left succeeds. If all three succeed, the break
exits the loop.
Upvotes: 3