5 kez çalıştırmayı tekrar denemek için komut dosyasında bir yeniden deneme mantığı nasıl yazarım?


112

Bir sorun nedeniyle başarısız olursa "status code = FAIL" 'a dayanarak 5 saniyeye kadar 15 saniye sonra tekrar çalışmayı deneyecek olan kabuk betiğine mantık yazmak istiyorum .

Yanıtlar:


90

Bu komut n, komuttaki girişimleri beş ile sınırlamak için bir sayaç kullanır . Eğer komut başarılı olursa, $?sıfırı tutacak ve yürütme döngüden kopacaktır.

n=0
until [ $n -ge 5 ]
do
   command && break  # substitute your command here
   n=$[$n+1]
   sleep 15
done

1
breakkomut başarılı olursa o zaman döngü kıracak
Rahul Patil

Aslında bunu yazmanın doğru yolu if command; then break; fiya da daha kısaca, sadececommand && break
üçlü,

1
"command", durumunu denetlemek istediğiniz komutun adıdır.
şüpheli

3
Komutun başarılı olup olmadığını bilmek için n'in sonunda beşe eşit olup olmadığını test edebileceğinize dikkat edin.
mattdm

4
Güzel çözüm - ancak narıza durumunda, çıkmadan önce bir kez daha gereksiz yere uyur.
ron rothman

126
for i in 1 2 3 4 5; do command && break || sleep 15; done

Komutunuzla "komutu" değiştirin. Bu, "status code = FAIL" ifadesinin sıfır olmayan herhangi bir dönüş kodu anlamına geldiğini varsayar.


Varyasyonlar:

{..}Sözdizimini kullanarak . Çoğu kabukta çalışır, ancak BusyBox'ta çalışmaz sh:

for i in {1..5}; do command && break || sleep 15; done

seqBaşarısız komutun çıkış kodunu kullanarak ve ileterek:

for i in $(seq 1 5); do command && s=0 && break || s=$? && sleep 15; done; (exit $s)

Yukarıdakiyle aynı, ancak sleep 15son başarısızlıktan sonra atlama . Maksimum döngü sayısını yalnızca bir kez tanımlamak daha iyi olduğundan, bu işlem aşağıdaki işlemlerin başında uyunarak gerçekleştirilir i > 1:

for i in $(seq 1 5); do [ $i -gt 1 ] && sleep 15; command && s=0 && break || s=$?; done; (exit $s)

25
+1 - özlü ve net. Bir öneri: Ben yerine geçer for i in 1 2 3 4 5, for i in {1..5}çünkü bakımı kolaydır.
Paddy Landau,

5
Sadece bir not, bu işe &&||
yarar

6
Başka bir not, bu commandbaşarısız olsa bile 0 kodunu döndürür .
Henrique Zambon

3
@HenriqueZambon Bunu da işleyen bir sürüm eklendi.
Alexander,

2
Bu son başarısızlıktan sonra uyumaz mı? Gereksiz bir 15 dakika beklemeye benziyor. Bunu [[ i -eq 5]]önlemek için uykudan önce bir VEYA durumu için bir kontrol koyabilirsiniz düşünüyorum .
Dave Lugg

32
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
}

Örnek:

retry ping invalidserver

bu çıktıyı üretir:

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

Gerçek dünya için karmaşık komutlarla çalışan bir örnek için bu senaryoya bakın .


3
Bu harika bir çözüm. Bir şey de birkaç kez başarısız olduktan sonra sıfır olmayan bir çıkış durumu ile çıkmasını seviyorum.
Ben Liyanage

11

İşte yeniden deneme işlevi

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 $*

Çıktı :

[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 ::

Kodunuzu retry.sh adlı yeni bir dosyaya yapıştırdım ve en üste #! / Bin / bash satırı ekledim. Açıklamada verilen komutlarla çalışırken, hiçbir şey sormadan tekrar gelir.
java_enthu

bash retry.sh 3 ping -c1 localhost
Denediniz

Evet Rahul denedim.
java_enthu

Üzgünüm, bizyindim .., tekrar test ettim, çalışıyor, çıktı paste.ubuntu.com/6002711 adresini ziyaret
Rahul Patil

Bu, şu ana kadarki en zarif cevap. Bu önemsiz şeyler yapıyorsanız. Zaman ayırdığınız için teşekkürler.
Jerry Andrews,

10

GNU Paralel vardır --retries:

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

5

İşte en sevdiğim bir satır diğer adı / script

    alias retry='while [ $? -ne 0 ] ; do fc -s ; done'

Sonra gibi şeyler yapabilirsiniz:

     $ ps -ef | grep "Next Process"
     $ retry

ve "Sonraki İşlem" i bulana kadar önceki komutu çalıştırmaya devam edecektir.


1
Zsh fc -e "#"yerine , kullanın fc -s.
Ricardo Stuven

2

Belirli bir komutun yeniden denenmesini sağlayan bu betiği kullanıyorum, bu betiğin yararı, tüm yeniden denemeleri başarısız olursa çıkış kodunu koruyacak olmasıdır.

#!/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

Muhtemelen daha basitleşebilir


Bu sürümün esnekliğini ve kodun ne kadar ayrıntılı ve okunaklı olduğunu seviyorum!
yo.ian.g

Başarısız olan yankıyı eşleştirmek için [$ ret_value -eq 0] ile başarılı bir yankı ekleyebilir veya daha sonra $ ret_value sınamasını bile yapabilirsiniz
yo.ian.g

Bu sürüm, komut son kez başarısız olduktan sonra uyumama avantajına sahiptir.
Alexander

1

Aşağıya bakınız Örnek:

n=0
while :
do
        nc -vzw1 localhost 3859
        [[ $? = 0 ]] && break || ((n++))
        (( n >= 5 )) && break

done

Bağlantı noktasını 3389'u localhost'a bağlamaya çalışıyorum, 5 kat başarısız oluncaya kadar tekrar deneyecek, eğer başarı olursa o zaman döngüyü kıracak.

$? sıfırın komutun başarıyla çalıştırıldığı anlamına gelirse, komutun durumu var

Biraz karışık görünüyor, birileri bundan daha iyisini yapabilir.


Teşekkürler rahul .. betiği çalıştırmak için yeniden denenecek mi ??
Sandeep Singh,

Lütfen şimdi kontrol et, Güncelleme yaptım
Rahul Patil

$?sıfır komutunun başarıyla çalıştırılması, sıfırın haricinde komutun başarısız olması anlamına gelirse, komutun var olduğu
Rahul Patil

ana bilgisayar ve bağlantı noktası adresi verilmesi gerekli midir? sadece script dir komutunu vererek bunu yapabiliriz.
Sandeep Singh,

$ çıkış durum kodunu veren herhangi bir komutla değiştirilsin mi?
Rahul Patil

1

Sen kullanabilirsiniz loopmevcut komutu, burada aynen böyle:

$ loop './do_thing.sh' --every 15s --until-success --num 5 

Bu, başarılı olana kadar her 15 saniyede bir, en fazla beş defa bir şey yapacak.


0

İşte retryfonksiyonel programlama uzmanları için özyinelemeli bir işlev:

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
}

Bir komut (veya bir işlev adı) ve isteğe bağlı olarak bir dizi yeniden deneme ve yeniden deneme arasında uyku süresi gibi, örneğin:

retry some_command_or_fn 5 15 # 5 tries, sleep 15 seconds between each

O vb borular için çalışır beklenen tamsayı ifadesi ... Ne: cmd = "yankı filan" ... hat 10: [: blah Bu, birden fazla kelime uzunluğunda komutlar için çalışmıyor
Mercury00
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.