web-dev-qa-db-fra.com

Comment puis-je écrire une logique de nouvelle tentative dans le script pour continuer à essayer de l'exécuter jusqu'à 5 fois?

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.

127
Sandeep Singh

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
109
suspectus
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.


Variations:

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)
138
Alexander
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 .

37
Fernando Correia

GNU Parallel a --retries:

parallel --retries 5 --delay 15s ::: ./do_thing.sh
11
Ole Tange

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 ::
11
Rahul Patil

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"

6
Jeff

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

2
padilo

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.

2
Rahul Patil

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.

1
Rich Jones

Répondre à cette question car les réponses existantes échouent,

  1. Ne lance pas de code d'erreur.
  2. En faisant 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
0
Pratap Koritala

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
0
Mikhail Vasin

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

0
Graham Leggett