Je veux écrire la logique dans le script Shell qui va réessayer de s'exécuter à nouveau après 15 secondes jusqu'à 5 fois en fonction de "code d'état = FAIL" s'il échoue en raison d'un problème.
Ce script utilise un compteur n
pour limiter les tentatives de commande à cinq. Si la commande réussit, $?
maintiendra zéro et l'exécution s'arrêtera de la boucle.
n=0
until [ $n -ge 5 ]
do
command && break # substitute your command here
n=$[$n+1]
sleep 15
done
for i in 1 2 3 4 5; do command && break || sleep 15; done
Remplacez "commande" par votre commande. Cela suppose que "code d'état = FAIL" signifie tout code retour différent de zéro.
En utilisant le {..}
syntaxe. Fonctionne dans la plupart des shells, mais pas dans BusyBox sh
:
for i in {1..5}; do command && break || sleep 15; done
Utilisation de seq
et transmission du code de sortie de la commande ayant échoué:
for i in $(seq 1 5); do command && s=0 && break || s=$? && sleep 15; done; (exit $s)
Comme ci-dessus, mais en sautant sleep 15
après l'échec final. Puisqu'il vaut mieux ne définir qu'une seule fois le nombre maximum de boucles, ceci est réalisé en dormant au début de la boucle si i > 1
:
for i in $(seq 1 5); do [ $i -gt 1 ] && sleep 15; command && s=0 && break || s=$?; done; (exit $s)
function fail {
echo $1 >&2
exit 1
}
function retry {
local n=1
local max=5
local delay=15
while true; do
"$@" && break || {
if [[ $n -lt $max ]]; then
((n++))
echo "Command failed. Attempt $n/$max:"
sleep $delay;
else
fail "The command has failed after $n attempts."
fi
}
done
}
Exemple:
retry ping invalidserver
produit cette sortie:
ping: unknown Host invalidserver
Command failed. Attempt 2/5:
ping: unknown Host invalidserver
Command failed. Attempt 3/5:
ping: unknown Host invalidserver
Command failed. Attempt 4/5:
ping: unknown Host invalidserver
Command failed. Attempt 5/5:
ping: unknown Host invalidserver
The command 'ping invalidserver' failed after 5 attempts
Pour un exemple de travail réel avec des commandes complexes, voir ce script .
GNU Parallel a --retries
:
parallel --retries 5 --delay 15s ::: ./do_thing.sh
Voici la fonction pour réessayer
function retry()
{
local n=0
local try=$1
local cmd="${@: 2}"
[[ $# -le 1 ]] && {
echo "Usage $0 <retry_number> <Command>"; }
until [[ $n -ge $try ]]
do
$cmd && break || {
echo "Command Fail.."
((n++))
echo "retry $n ::"
sleep 1;
}
done
}
retry $*
Sortie:
[test@Nagios ~]$ ./retry.sh 3 ping -c1 localhost
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.207 ms
--- localhost ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.207/0.207/0.207/0.000 ms
[test@Nagios ~]$ ./retry.sh 3 ping -c1 localhostlasjflasd
ping: unknown Host localhostlasjflasd
Command Fail..
retry 1 ::
ping: unknown Host localhostlasjflasd
Command Fail..
retry 2 ::
ping: unknown Host localhostlasjflasd
Command Fail..
retry 3 ::
Voici mon alias/script préféré d'une ligne
alias retry='while [ $? -ne 0 ] ; do fc -s ; done'
Ensuite, vous pouvez faire des choses comme:
$ ps -ef | grep "Next Process"
$ retry
et il continuera d'exécuter la commande précédente jusqu'à ce qu'il trouve "Prochain processus"
J'utilise ce script qui fait les tentatives d'une commande donnée, l'avantage de ce script est que si échoue toutes les tentatives, il conservera le code de sortie.
#!/usr/bin/env bash
if [ $# -ne 3 ]; then
echo 'usage: retry <num retries> <wait retry secs> "<command>"'
exit 1
fi
retries=$1
wait_retry=$2
command=$3
for i in `seq 1 $retries`; do
echo "$command"
$command
ret_value=$?
[ $ret_value -eq 0 ] && break
echo "> failed with $ret_value, waiting to retry..."
sleep $wait_retry
done
exit $ret_value
Cela peut probablement devenir plus simple
Voir ci-dessous Exemple:
n=0
while :
do
nc -vzw1 localhost 3859
[[ $? = 0 ]] && break || ((n++))
(( n >= 5 )) && break
done
J'essaie de connecter le port 3389 sur localhost, il réessayera jusqu'à 5 échecs, en cas de succès, il rompra la boucle.
$?
il existe l'état de la commande si zéro signifie que la commande a été exécutée avec succès, si autre que zéro signifie que la commande fai
Cela semble un peu compliqué, peut-être que quelqu'un le fait mieux que cela.
Vous pouvez utiliser la commande loop
, disponible ici , comme ceci:
$ loop './do_thing.sh' --every 15s --until-success --num 5
Ce qui fera votre truc toutes les 15 secondes jusqu'à ce qu'il réussisse, pour un maximum de cinq fois.
Répondre à cette question car les réponses existantes échouent,
exit errCode
, Bash n'honore pas certains pièges tels que trap somefunc ERR
COMMAND="SOMECOMMAND"
TOTAL_RETRIES=3
retrycount=0
until [ $retrycount -ge $((TOTAL_RETRIES-1)) ]
do
$COMMAND && break
retrycount=$((retrycount+1))
sleep 1
done
if [ $retrycount -eq $((TOTAL_RETRIES-1)) ]
then
$COMMAND
fi
Voici une fonction récursive retry
pour les puristes de la programmation fonctionnelle:
retry() {
cmd=$1
try=${2:-15} # 15 by default
sleep_time=${3:-3} # 3 seconds by default
# Show help if a command to retry is not specified.
[ -z "$1" ] && echo 'Usage: retry cmd [try=15 sleep_time=3]' && return 1
# The unsuccessful recursion termination condition (if no retries left)
[ $try -lt 1 ] && echo 'All retries failed.' && return 1
# The successful recursion termination condition (if the function succeeded)
$cmd && return 0
echo "Execution of '$cmd' failed."
# Inform that all is not lost if at least one more retry is available.
# $attempts include current try, so tries left is $attempts-1.
if [ $((try-1)) -gt 0 ]; then
echo "There are still $((try-1)) retrie(s) left."
echo "Waiting for $sleep_time seconds..." && sleep $sleep_time
fi
# Recurse
retry $cmd $((try-1)) $sleep_time
}
Passez-lui une commande (ou un nom de fonction) et éventuellement un certain nombre de tentatives et une durée de sommeil entre les tentatives, comme ceci:
retry some_command_or_fn 5 15 # 5 tries, sleep 15 seconds between each
Ayant besoin de le faire plusieurs fois, le script devenait incontrôlable, j'ai donc créé un outil dédié pour cette nouvelle tentative.
retry --until=success --times=5 --delay=15 command ...
Réessayer est disponible ici: https://github.com/minfrin/retry