Je veux écrire la logique dans un script shell qui le réessayera de s'exécuter de 15 à 5 secondes en fonction du "code d'état = FAIL" s'il échoue à cause d'un problème.
Je veux écrire la logique dans un script shell qui le réessayera de s'exécuter de 15 à 5 secondes en fonction du "code d'état = FAIL" s'il échoue à cause d'un problème.
Réponses:
Ce script utilise un compteur n
pour limiter le nombre de tentatives à la commande à cinq. Si la commande aboutit, sa valeur $?
sera égale à zéro et l'exécution sera interrompue.
n=0
until [ $n -ge 5 ]
do
command && break # substitute your command here
n=$[$n+1]
sleep 15
done
if command; then break; fi
ou plus succinctement justecommand && break
n
échec, il dort inutilement une fois de plus avant de sortir.
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" désigne tout code de retour différent de zéro.
Utiliser la {..}
syntaxe. Fonctionne dans la plupart des shells, mais pas dans BusyBox sh
:
for i in {1..5}; do command && break || sleep 15; done
Utilisation 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. Dans la mesure où il est préférable de définir le nombre maximal de boucles une seule fois, vous pouvez vous mettre en veille 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)
for i in 1 2 3 4 5
par for i in {1..5}
parce que c'est plus facile à maintenir.
command
échoue.
[[ i -eq 5]]
comme condition d’opération avant le sommeil pour éviter cela.
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 concret, avec des commandes complexes, voir ce script .
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 ::
bash retry.sh 3 ping -c1 localhost
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 à exécuter la commande précédente jusqu'à ce qu'il trouve "Prochain processus"
fc -e "#"
place de fc -s
.
J'utilise ce script qui effectue les tentatives d'une commande donnée. L'avantage de ce script est que si toutes les tentatives échouent, le code de sortie est préservé.
#!/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
Probablement cela peut devenir plus simple
Voir ci-dessous Exemple:
n=0
while :
do
nc -vzw1 localhost 3859
[[ $? = 0 ]] && break || ((n++))
(( n >= 5 )) && break
done
J'essaye de connecter le port 3389 sur localhost, il essaiera jusqu'à 5 fois d'échouer, en cas de succès, il cassera la boucle.
$?
il existe un statut de commande si zéro signifie une commande exécutée avec succès, si autre que zéro signifie une commande fai
Cela semble un peu compliqué, peut-être que quelqu'un le fera mieux que cela.
$?
il existe un statut de commande si zéro signifie une commande exécutée avec succès, si autre que zéro signifie une commande échouée
Vous pouvez utiliser la loop
commande, disponible ici , comme suit:
$ loop './do_thing.sh' --every 15s --until-success --num 5
Ce qui fera votre chose toutes les 15 secondes jusqu'à ce qu'il réussisse, pour un maximum de cinq fois.
Voici une retry
fonction récursive 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
}
Transmettez-lui une commande (ou un nom de fonction) et éventuellement un nombre de tentatives et une durée de veille entre les tentatives, comme suit:
retry some_command_or_fn 5 15 # 5 tries, sleep 15 seconds between each
break
si la commande réussit, la boucle sera rompue