Ich möchte eine Logik in ein Shell-Skript schreiben, das versucht, es nach 15 Sekunden bis zu 5 Mal erneut auszuführen, basierend auf "status code = FAIL", wenn es aufgrund eines Problems fehlschlägt.
Ich möchte eine Logik in ein Shell-Skript schreiben, das versucht, es nach 15 Sekunden bis zu 5 Mal erneut auszuführen, basierend auf "status code = FAIL", wenn es aufgrund eines Problems fehlschlägt.
Antworten:
Dieses Skript verwendet einen Zähler n
, um die Versuche, den Befehl auszuführen, auf fünf zu beschränken. Wenn der Befehl erfolgreich ist, $?
wird Null gehalten und die Ausführung wird von der Schleife abgebrochen.
n=0
until [ $n -ge 5 ]
do
command && break # substitute your command here
n=$[$n+1]
sleep 15
done
if command; then break; fi
oder genauer command && break
n
Ausfällen wird vor dem Beenden unnötigerweise ein weiteres Mal geschlafen.
for i in 1 2 3 4 5; do command && break || sleep 15; done
Ersetzen Sie "command" durch Ihren Befehl. Dies setzt voraus, dass "Statuscode = FAIL" einen beliebigen Rückkehrcode ungleich Null bedeutet.
Verwenden der {..}
Syntax. Funktioniert in den meisten Shells, aber nicht in BusyBox sh
:
for i in {1..5}; do command && break || sleep 15; done
Verwendung seq
und Weitergabe entlang der Beendigungscode des ausgefallenen Befehl:
for i in $(seq 1 5); do command && s=0 && break || s=$? && sleep 15; done; (exit $s)
Wie oben, aber sleep 15
nach dem endgültigen Fehlschlag überspringen . Da es besser ist, die maximale Anzahl von Schleifen nur einmal zu definieren, wird dies erreicht, indem am Anfang der Schleife geschlafen wird, wenn 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
mit , for i in {1..5}
weil es leichter zu pflegen.
command
fehlschlägt.
[[ i -eq 5]]
vor dem Schlafengehen eine OP- Prüfung durchführen , um dies zu vermeiden.
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
}
Beispiel:
retry ping invalidserver
erzeugt diese Ausgabe:
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
Ein reales Beispiel für die Arbeit mit komplexen Befehlen finden Sie in diesem Skript .
Hier ist die Funktion für einen erneuten Versuch
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 $*
Ausgabe :
[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
Hier ist mein Lieblings-Alias / Skript für eine Zeile
alias retry='while [ $? -ne 0 ] ; do fc -s ; done'
Dann kannst du Sachen machen wie:
$ ps -ef | grep "Next Process"
$ retry
und es wird den vorherigen Befehl so lange ausführen, bis es "Nächster Prozess" findet
fc -e "#"
anstelle von fc -s
.
Ich verwende dieses Skript, das die Wiederholungen eines bestimmten Befehls durchführt. Der Vorteil dieses Skripts besteht darin, dass der Exit-Code erhalten bleibt, wenn alle Wiederholungen fehlschlagen.
#!/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
Wahrscheinlich kann es einfacher werden
Siehe unten Beispiel:
n=0
while :
do
nc -vzw1 localhost 3859
[[ $? = 0 ]] && break || ((n++))
(( n >= 5 )) && break
done
Ich versuche, Port 3389 auf localhost zu verbinden. Der Versuch wird wiederholt, bis fünfmal ein Fehler auftritt. Bei Erfolg wird die Schleife unterbrochen.
$?
Der Status des Befehls ist vorhanden, wenn Null bedeutet, dass der Befehl erfolgreich ausgeführt wurde. Wenn nicht Null, bedeutet dies, dass der Befehl fai ausgeführt wurde
Scheint ein bisschen kompliziert, kann jemand es besser machen.
$?
es ist Status des Befehls gegeben , wenn es Null bedeutet , erfolgreich Befehl ausführen, wenn andere als Null bedeutet Befehl fehl
Sie können den hierloop
verfügbaren Befehl folgendermaßen verwenden :
$ loop './do_thing.sh' --every 15s --until-success --num 5
Das macht dein Ding alle 15 Sekunden, bis es erfolgreich ist, maximal fünf Mal.
Hier ist eine rekursive retry
Funktion für Puristen der funktionalen Programmierung:
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
}
Übergeben Sie einen Befehl (oder einen Funktionsnamen) und optional eine Anzahl von Wiederholungen und eine Ruhezeit zwischen den Wiederholungen, wie folgt:
retry some_command_or_fn 5 15 # 5 tries, sleep 15 seconds between each
break
wenn der Befehl erfolgreich ist, dann wird er die Schleife