मैं इसे 5 बार तक चलाने के लिए पुन: प्रयास करने के लिए स्क्रिप्ट में एक रिट्री लॉजिक कैसे लिखूं?


112

मैं शेल स्क्रिप्ट में तर्क लिखना चाहता हूं जो "स्टेटस कोड = फेल " के आधार पर 5 सेकंड तक 15 सेकंड के बाद फिर से चलाने के लिए इसे फिर से चलाएगा यदि यह किसी मुद्दे के कारण विफल हो जाता है।

जवाबों:


90

यह स्क्रिप्ट nकमांड पर प्रयासों को पाँच तक सीमित करने के लिए एक काउंटर का उपयोग करती है। यदि कमांड सफल होता है, $?तो शून्य पकड़ लेगा और निष्पादन लूप से टूट जाएगा।

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

1
आप जोड़ना चाहिए breakअगर आदेश सफलताओं तो यह पाश टूट जाएगा
राहुल पाटिल

वास्तव में यह लिखने का उचित तरीका है कि if command; then break; fiया अधिक command && break
रसीले तरीके से

1
"कमांड" केवल उस कमांड का नाम है जिसे आप स्थिति की जांच करना चाहते हैं।
शक

3
वर्थ नोटिंग कि आप परीक्षण कर सकते हैं कि क्या कमांड सफल हुआ या नहीं, यह जानने के लिए n अंत में पांच के बराबर है।
mattdm

4
अच्छा समाधान - लेकिन nविफलताओं के मामले में , यह अनावश्यक रूप से बाहर निकलने से पहले एक अतिरिक्त समय सोता है।
रॉन रोथमैन

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

"कमांड" को अपनी कमांड से बदलें। यह मानकर चल रहा है कि "स्थिति कोड = विफल" का अर्थ किसी भी गैर-शून्य रिटर्न कोड से है।


बदलाव:

{..}वाक्य रचना का उपयोग करना । अधिकांश गोले में काम करता है, लेकिन बिजीबॉक्स नहीं sh:

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

seqअसफल कमांड के निकास कोड का उपयोग करना और पास करना :

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

ऊपर के समान, लेकिन sleep 15अंतिम असफल होने के बाद लंघन । चूंकि केवल लूप की अधिकतम संख्या को एक बार परिभाषित करना बेहतर है, यह लूप की शुरुआत में सोने से प्राप्त होता है यदि i > 1:

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

25
+1 - रसीला और स्पष्ट। एक सुझाव यह है: मैं की जगह लेंगे for i in 1 2 3 4 5साथ for i in {1..5}है क्योंकि यह बनाए रखने के लिए आसान है।
धान लैंडौ

5
बस एक ध्यान दें, यह काम करता है क्योंकि &&इससे पहले मूल्यांकन किया जाता है ||की वजह से ऑपरेटर पूर्वता
gene_wood

6
एक और नोट, यह कोड 0 वापस कर देगा भले ही commandविफल हो।
हेनरिक जाम्बोन

3
@HenriqueZambon ने एक संस्करण जोड़ा जो भी संभालता है।
अलेक्जेंडर

2
क्या यह अंतिम विफलता के बाद नहीं सोता है? एक अनावश्यक 15 की प्रतीक्षा की तरह लगता है। मुझे लगता है कि [[ i -eq 5]]इससे बचने के लिए आप सोने से पहले एक OR स्थिति के रूप में चेक लगा सकते हैं ।
डेव लुग

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
}

उदाहरण:

retry ping invalidserver

इस उत्पादन का उत्पादन:

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

एक वास्तविक दुनिया के लिए, जटिल आदेशों के साथ काम करने का उदाहरण, इस स्क्रिप्ट को देखें ।


3
यह एक बेहतरीन उपाय है। मुझे पसंद है कि यह एक गैर-शून्य निकास स्थिति के साथ बाहर निकलता है क्योंकि कुछ भी कई बार विफल हो गया है।
बेन लियायनएज

11

यहाँ पुनः प्रयास के लिए कार्य किया गया है

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

आउटपुट:

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

मैंने आपके कोड को एक नई फ़ाइल में कॉपी किया है जिसे रिट्री.श कहा जाता है और शीर्ष पर एक लाइन #! / Bin / bash जोड़ा है। स्पष्टीकरण में आपके दिए गए आदेशों के साथ चलने के दौरान मुझे कुछ भी दिखाई नहीं देता है, बस फिर से संकेत मिलता है।
java_enthu

क्या आपने कोशिश की हैbash retry.sh 3 ping -c1 localhost
राहुल पाटिल

हां राहुल मैंने कोशिश की।
java_enthu

क्षमा करें, मैं बिज़ी था .., मैंने फिर से परीक्षण किया है, यह काम कर रहा है, आउटपुट पेस्ट की
राहुल पाटिल

यह अब तक का सबसे सुरुचिपूर्ण उत्तर है - यदि आप कुछ गैर-तुच्छ कर रहे हैं। समय लेने के लिए शुक्रिया।
जेरी एंड्रयूज


5

यहाँ मेरा पसंदीदा एक लाइन उर्फ ​​/ स्क्रिप्ट है

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

फिर आप सामान की तरह कर सकते हैं:

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

और जब तक यह "नेक्स्ट प्रोसेस" नहीं मिल जाता, तब तक यह पूर्व कमांड को चालू रखेगा।


1
Zsh में, के fc -e "#"बजाय का उपयोग करें fc -s
रिकार्डो स्टुवेन

2

मैं इस स्क्रिप्ट का उपयोग करता हूं जो किसी दिए गए कमांड के रिट्रीट को बनाता है, इस स्क्रिप्ट का लाभ यह है कि यदि सभी रिट्स विफल हो जाते हैं तो यह निकास कोड को संरक्षित करेगा।

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

संभवतः यह सरल हो सकता है


मुझे पसंद है कि यह संस्करण कितना लचीला है और कोड कितना वाचाल और पठनीय है!
yo.ian.g

असफल प्रतिध्वनि से मेल खाने के लिए आप [$ ret_value -eq 0] के साथ एक सफल प्रतिध्वनि भी जोड़ सकते हैं या बाद में $ ret_value का परीक्षण कर सकते हैं
yo.ian.g

अंतिम समय तक आदेश विफल होने के बाद इस संस्करण को नहीं सोने का लाभ है।
अलेक्जेंडर

1

नीचे देखें उदाहरण:

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

done

मैं लोकलहोस्ट पर पोर्ट 3389 को जोड़ने की कोशिश कर रहा हूं, यह 5 बार विफल होने तक पीछे हट जाएगा, अगर सफलता मिलती है तो यह लूप तोड़ देगा।

$? यदि शून्य का अर्थ है, तो कमांड की स्थिति मौजूद है यदि इसका मतलब है कि कमांड सफलतापूर्वक चलता है, यदि शून्य के अलावा अन्य कमांड कमांड का मतलब है

थोड़ा जटिल लगता है, हो सकता है कि कोई इसे इससे बेहतर करे।


धन्यवाद rahul .. क्या यह स्क्रिप्ट को चलाने के लिए पुनः प्रयास करना होगा ??
संदीप सिंह

कृपया अब जांचें, मैंने अपडेट किया है
राहुल पाटिल

$?यदि यह शून्य का मतलब है कि यह कमांड की स्थिति मौजूद है, तो कमांड सफलतापूर्वक चलता है, यदि शून्य से अन्य का मतलब कमांड फेल है
राहुल पाटिल

क्या होस्ट और पोर्ट एड्रेस देना आवश्यक है क्या हम इसे स्क्रिप्ट लोकेशन डीआईआर देकर ही कर सकते हैं।
संदीप सिंह

किसी भी आदेश के साथ बदलें जो निकास स्थिति कोड $ दे?
राहुल पाटिल

1

आप यहांloop उपलब्ध कमांड का उपयोग कर सकते हैं , जैसे:

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

जो आपकी सफलता को हर 15 सेकंड में करेगा, जब तक कि वह सफल न हो जाए, अधिकतम पांच बार।


0

यहाँ retryकार्यात्मक प्रोग्रामिंग purists के लिए एक पुनरावर्ती कार्य है:

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
}

इसे एक कमांड (या एक फ़ंक्शन नाम) पास करें और वैकल्पिक रूप से कई रिट्रीट और रिट्रीट के बीच एक नींद की अवधि, जैसे:

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

यह एक से अधिक शब्द लंबे समय तक काम नहीं करता है: cmd = "इको ब्ला ब्ला" ... पंक्ति 10: [: blah: पूर्णांक अभिव्यक्ति अपेक्षित ... न ही यह पाइपों के लिए काम करता है, आदि
Mercury00
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.