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.