【问题标题】:Retry a Bash command with timeout超时重试 Bash 命令
【发布时间】:2012-09-01 12:51:40
【问题描述】:

如何重试 bash 命令直到其状态正常或达到超时?

我最好的镜头(我正在寻找更简单的东西):

NEXT_WAIT_TIME=0
COMMAND_STATUS=1
until [ $COMMAND_STATUS -eq 0 || $NEXT_WAIT_TIME -eq 4 ]; do
  command
  COMMAND_STATUS=$?
  sleep $NEXT_WAIT_TIME
  let NEXT_WAIT_TIME=NEXT_WAIT_TIME+1
done

【问题讨论】:

标签: bash loops timeout


【解决方案1】:

您可以通过将command 放在测试中并以不同的方式进行增量来简化事情。否则脚本看起来不错:

NEXT_WAIT_TIME=0
until [ $NEXT_WAIT_TIME -eq 5 ] || command; do
    sleep $(( NEXT_WAIT_TIME++ ))
done
[ $NEXT_WAIT_TIME -lt 5 ]

【讨论】:

  • 至少在 bash 版本 4.1.5 中您需要将 sleep 行更改为 sleep $(( NEXT_WAIT_TIME++ ))
  • 谢谢,已解决。
  • 很好的解决方案,唯一的问题是在最后一个“命令”失败后,你仍然需要休眠 4 秒。不确定是否可以避免这种情况并保持代码紧凑。
  • @David 真的吗?如果左侧返回真值,|| 运算符会评估右侧吗? (我不太了解 bash,我只知道在 javascript 中不会。)
  • @David 在最后一次迭代中,|| 的 RHS 将为真,因此 sleep 不会发生
【解决方案2】:

一条线最短,也许是最好的方法:

timeout 12h bash -c 'until ssh root@mynewvm; do sleep 10; done'

感谢http://jeromebelleman.gitlab.io/posts/devops/until/

【讨论】:

  • 我认为对于大多数目的来说这是最好的答案。如果您需要更多笨拙的代码,您可以使用函数。然而,它使您试图实现的主要目标足够短,以便于理解。
【解决方案3】:

重试函数来自:

http://fahdshariff.blogspot.com/2014/02/retrying-commands-in-shell-scripts.html

#!/bin/bash

# Retries a command on failure.
# $1 - the max number of attempts
# $2... - the command to run
retry() {
    local -r -i max_attempts="$1"; shift
    local -r cmd="$@"
    local -i attempt_num=1

    until $cmd
    do
        if (( attempt_num == max_attempts ))
        then
            echo "Attempt $attempt_num failed and there are no more attempts left!"
            return 1
        else
            echo "Attempt $attempt_num failed! Trying again in $attempt_num seconds..."
            sleep $(( attempt_num++ ))
        fi
    done
}

# example usage:
retry 5 ls -ltr foo

如果你想在你的脚本中重试一个函数,你应该这样做:

# example usage:
foo()
{
   #whatever you want do.
}

declare -fxr foo
retry 3 timeout 60 bash -ce 'foo'

【讨论】:

    【解决方案4】:

    把一些工具放在一起。

    重试:https://github.com/kadwanev/retry

    超时:http://manpages.courier-mta.org/htmlman1/timeout.1.html

    然后看看魔法

    retry timeout 3 ping google.com
    
    PING google.com (173.194.123.97): 56 data bytes
    64 bytes from 173.194.123.97: icmp_seq=0 ttl=55 time=13.982 ms
    64 bytes from 173.194.123.97: icmp_seq=1 ttl=55 time=44.857 ms
    64 bytes from 173.194.123.97: icmp_seq=2 ttl=55 time=64.187 ms
    Before retry #1: sleeping 0.3 seconds
    PING google.com (173.194.123.103): 56 data bytes
    64 bytes from 173.194.123.103: icmp_seq=0 ttl=55 time=56.549 ms
    64 bytes from 173.194.123.103: icmp_seq=1 ttl=55 time=60.220 ms
    64 bytes from 173.194.123.103: icmp_seq=2 ttl=55 time=8.872 ms
    Before retry #2: sleeping 0.6 seconds
    PING google.com (173.194.123.103): 56 data bytes
    64 bytes from 173.194.123.103: icmp_seq=0 ttl=55 time=25.819 ms
    64 bytes from 173.194.123.103: icmp_seq=1 ttl=55 time=16.382 ms
    64 bytes from 173.194.123.103: icmp_seq=2 ttl=55 time=3.224 ms
    Before retry #3: sleeping 1.2 seconds
    PING google.com (173.194.123.103): 56 data bytes
    64 bytes from 173.194.123.103: icmp_seq=0 ttl=55 time=58.438 ms
    64 bytes from 173.194.123.103: icmp_seq=1 ttl=55 time=94.828 ms
    64 bytes from 173.194.123.103: icmp_seq=2 ttl=55 time=61.075 ms
    Before retry #4: sleeping 2.4 seconds
    PING google.com (173.194.123.103): 56 data bytes
    64 bytes from 173.194.123.103: icmp_seq=0 ttl=55 time=43.361 ms
    64 bytes from 173.194.123.103: icmp_seq=1 ttl=55 time=32.171 ms
    ...
    

    检查最终通过/失败的退出状态。

    【讨论】:

      【解决方案5】:

      我对@9​​87654321@ 回答做了一些调整,让您可以切换是否达到超时,或者命令是否成功。此外,在此版本中,每秒重试一次:

      ELAPSED=0
      started=$(mktemp)
      echo "False" > $started
      until the_command_here && echo "True" > $started || [ $ELAPSED -eq 30 ]
      do
         sleep 1
         (( ELAPSED++ ))
      done
      
      if [[ $(cat $started) == "True" ]]                                                                                                                                                                                                                            
      then                                                                                                                    
          echo "the command completed after $ELAPSED seconds"                                                                                              
      else                                                                                                                    
          echo "timed out after $ELAPSED seconds"                                                                               
          exit 111                                                                                                            
      fi
      

      【讨论】:

        【解决方案6】:

        对于任何想要真正等到一段时间过去的人来说,考虑到你的命令时间可能很重要:

        TIMEOUT_SEC=180
        start_time="$(date -u +%s)"
        while [ condition_or_just_true ]; do
          current_time="$(date -u +%s)"
          elapsed_seconds=$(($current_time-$start_time))
          if [ $elapsed_seconds -gt $TIMEOUT_SEC ]; then
            echo "timeout of $TIMEOUT_SEC sec"
            exit 1
          fi
          echo "another attempt (elapsed $elapsed_seconds sec)"
          some_command_and_maybe_sleep
        done
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-04-22
          • 2013-08-07
          • 1970-01-01
          • 2012-03-06
          • 2016-10-25
          • 2018-10-28
          • 1970-01-01
          • 2021-09-06
          相关资源
          最近更新 更多