スクリプトで再試行ロジックを5回まで再試行し続けるにはどうすればよいですか?


112

何らかの問題が原因で失敗した場合、"status code = FAIL"に基づいて15秒後に5回まで再試行するロジックをシェルスクリプトに記述します。

回答:


90

このスクリプトは、カウンターnを使用して、コマンドの試行回数を5回に制限します。コマンドが成功すると、$?ゼロを保持し、実行がループから中断します。

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
-tripleee

1
「command」は、ステータスを確認するコマンドの名前です。
容疑者

3
コマンドが成功したかどうかを知るために、nが最後に5に等しいかどうかをテストできることに注意してください。
mattdm

4
素晴らしい解決策ですが、n障害が発生した場合は、終了する前に1回余分にスリープします。
ロンロスマン

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

「コマンド」をコマンドに置き換えます。これは、「ステータスコード= FAIL」がゼロ以外のリターンコードを意味すると想定しています。


バリエーション:

{..}構文を使用します。ほとんどのシェルで動作しますが、BusyBoxでは動作しません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 —簡潔かつ明確。1つの提案:私が代わるfor i in 1 2 3 4 5for i in {1..5}、それは保守が簡単だからです。
水田ランダウ

5
注:これ&&||演算子の優先順位
-gene_wood

6
別の注意として、これはcommand失敗してもコード0を返します。
エンリケザンボン

3
@HenriqueZambonはそれも処理するバージョンを追加しました。
アレクサンダー

2
これは最終的な失敗の後に眠りませんか?不要な15秒の待機のようです。[[ i -eq 5]]これを回避するために、スリープ前にOR条件としてチェックを入れられると思います。
デイブ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
}

例:

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

retry.shという新しいファイルに貼り付けたコードをコピーし、先頭に#!/ bin / bashという行を追加しました。説明で指定されたコマンドで実行している間、プロンプトが再び表示されることはありません。
java_enthu

あなたは試してみましたbash retry.sh 3 ping -c1 localhost
ラーフルパティル

はい、Rahul試しました。
java_enthu

申し訳ありませんが、私は出力チェック、働いている、...、私は再びテストしているbizyたpaste.ubuntu.com/6002711
ラーフルパティル

これはここまでで最もエレガントな答えです-あなたが些細ではない何かをしているなら。お時間をいただきありがとうございます。
ジェリーアンドリュース


5

これが私のお気に入りの1行のエイリアス/スクリプトです

    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

localhostのポート3389に接続しようとしていますが、5回失敗するまで再試行します。成功した場合はループを中断します。

$? ゼロがコマンドの正常な実行を意味する場合、コマンドのステータスが存在します。ゼロ以外がコマンドfaiを意味する場合

少し複雑に思えますが、誰かがこれよりもうまくやるかもしれません。


rahul ..に感謝します。スクリプトを再試行し続けますか??
サンディープシン

今確認してください、私は更新されている
ラーフルパティル

$?それはゼロコマンドが正常に実行を意味する場合は、ゼロ以外のコマンドは失敗を意味している場合には、コマンドのステータスを存在だ
ラーフルパティル

ホストとポートのアドレスを指定する必要がありますか?スクリプトの場所をディレクトリのみに指定することでそれを行うことができます。
サンディープシン

終了ステータスコード$?を与えるコマンドに置き換えます。
ラーフルパティル


0

retry関数型プログラミングの純粋主義者向けの再帰関数は次のとおりです。

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行目:[:何とかこれは、複数の単語長いコマンドのために動作しません
Mercury00
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.