如何在脚本中编写重试逻辑以继续重试最多运行 5 次?

San*_*ngh 167 shell-script

我想在 shell 脚本中编写逻辑,如果由于某些问题而失败,它将根据“状态代码 = FAIL”在 15 秒后重试运行最多 5 次。

Ale*_*der 189

for i in 1 2 3 4 5; do command && break || sleep 15; done
Run Code Online (Sandbox Code Playgroud)

用您的命令替换“命令”。这是假设“状态代码=失败”意味着任何非零返回代码。


变化:

使用{..}语法。适用于大多数 shell,但不适用于 BusyBox sh

for i in {1..5}; do command && break || sleep 15; done
Run Code Online (Sandbox Code Playgroud)

使用seq并传递失败命令的退出代码:

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

同上,但sleep 15在最终失败后跳过。由于最好只定义一次最大循环数,这是通过在循环开始时休眠来实现的,如果i > 1

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

  • 请注意,这是有效的,因为 `&&` 在 `||` 之前被评估,因为 [operator precedence](http://tldp.org/LDP/abs/html/opprecedence.html) (9认同)
  • @Mausy5043,对于这种情况,这并不重要,因为 `s=0` 为 true,并且 `break` 打破了循环。 (2认同)

sus*_*tus 151

此脚本使用计数器n将命令的尝试次数限制为五次。如果命令成功,$?将保持为零并且执行将从循环中中断。

n=0
until [ "$n" -ge 5 ]
do
   command && break  # substitute your command here
   n=$((n+1)) 
   sleep 15
done
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,您可以测试最后 n 是否等于 5,以了解命令是否成功。 (3认同)
  • 上述的一个缺点是它在最后一次失败后休眠。 (3认同)

Fer*_*eia 48

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
}
Run Code Online (Sandbox Code Playgroud)

例子:

retry ping invalidserver
Run Code Online (Sandbox Code Playgroud)

产生这个输出:

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
Run Code Online (Sandbox Code Playgroud)

有关具有复杂命令的真实工作示例,请参阅此脚本


Ole*_*nge 19

GNU Parallel 具有--retries

parallel --retries 5 --delay 15s ::: ./do_thing.sh
Run Code Online (Sandbox Code Playgroud)

例子:

parallel -t --retries 5 --delay 0.1s 'echo {};exit {}' ::: {0..10}
Run Code Online (Sandbox Code Playgroud)

  • 你测试了吗?`--retries` 适用于本地和远程作业。但是对于远程作业,如果可能的话,GNU Parallel 会尝试在另一台服务器上重试作业(也许这个作业和那个服务器由于某种未知原因不喜欢彼此)。 (2认同)
  • 并行的 --help 可能会更好。总的来说,它是一个开发良好的工具,当然优于其他替代品,但有一些小缺点。(至少自从引用 nagscreen 消失后,这对我来说是不行的。)顺便说一句:--delay 不仅仅延迟重试,它延迟了一切。据我所知,目前还没有仅在错误时延迟的功能(很有用 (2认同)

Rah*_*til 12

这是重试的功能

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 $*
Run Code Online (Sandbox Code Playgroud)

输出 :

[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 ::
Run Code Online (Sandbox Code Playgroud)


小智 12

这是我最喜欢的一行别名/脚本

    alias retry='while [ $? -ne 0 ] ; do fc -s ; done'
Run Code Online (Sandbox Code Playgroud)

然后你可以做这样的事情:

     $ ps -ef | grep "Next Process"
     $ retry
Run Code Online (Sandbox Code Playgroud)

它将继续运行先前的命令,直到找到“下一个进程”

  • 在 zsh 中,使用 `fc -e "#"` 而不是 `fc -s`。 (3认同)

Gra*_*ett 10

由于需要多次执行此操作,脚本变得失控,因此我为此创建了一个专用工具,称为重试。

retry --until=success --times=5 --delay=15 command ...
Run Code Online (Sandbox Code Playgroud)

如果您需要多个命令,您可以使用sh -c,例如

retry -- sh -c 'date && false'
Run Code Online (Sandbox Code Playgroud)

可以在这里重试: https: //github.com/minfrin/retry

  • 并且位于 Ubuntu 的官方存储库中 [自 20.04 LTS 起](https://packages.ubuntu.com/focal/retry) (2认同)

小智 5

我使用这个脚本来重试给定的命令,这个脚本的好处是,如果所有重试都失败,它将保留退出代码。

#!/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
Run Code Online (Sandbox Code Playgroud)

也许它可以变得更简单


小智 5

您可以使用此处loop提供的命令,如下所示:

$ loop './do_thing.sh' --every 15s --until-success --num 5 
Run Code Online (Sandbox Code Playgroud)

它将每 15 秒执行一次您的操作,直到成功为止,最多执行 5 次。