스크립트에 재시도 로직을 작성하여 5 회까지 다시 실행하려면 어떻게합니까?


112

일부 문제로 인해 "상태 코드 = FAIL" 에 따라 15 초 후 5 번까지 다시 실행되도록 셸 스크립트에 논리를 작성하려고합니다 .

답변:


90

이 스크립트는 카운터 n를 사용 하여 명령 시도를 5 개로 제한합니다. 명령이 성공 $?하면 0을 유지하고 루프에서 실행이 중단됩니다.

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"는 상태를 확인하려는 명령의 이름입니다.
suspectus

3
명령의 성공 여부를 알기 위해 마지막에 n이 5와 같은지 테스트 할 수 있습니다.
mattdm

4
좋은 해결책이지만 n장애가 발생한 경우 종료하기 전에 한 번 더 잠을 자지 않습니다.
ron rothman

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

"command"를 명령으로 바꾸십시오. "status code = FAIL"은 0이 아닌 리턴 코드를 의미한다고 가정합니다.


변형 :

{..}구문을 사용 합니다. 대부분의 쉘에서 작동하지만 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 — 간결하고 명확합니다. 한 가지 제안 : 나는 대체 할 for i in 1 2 3 4 5for i in {1..5}는 유지하기 쉽기 때문.
Paddy Landau

5
때문에 그냥 참고이 작동 &&하기 전에 평가하는 ||이유로 인해 연산자 우선 순위
gene_wood

6
또 다른 메모는 command실패 하더라도 코드 0을 반환 합니다.
Henrique Zambon

3
@HenriqueZambon 또한 처리하는 버전을 추가했습니다.
Alexander

2
마지막 실패 후 잠이 안됩니까? 불필요한 15 초 대기 인 것 같습니다. 나는 [[ i -eq 5]]이것을 피하기 위해 수면 전에 OR 상태로 검사를 할 수 있다고 생각합니다 .
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
}

예:

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
이것은 훌륭한 솔루션입니다. 나는 여러 번 실패한 후에도 0이 아닌 종료 상태로 종료되는 것을 좋아합니다.
Ben Liyanage

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 Patil

네 라훌은 시도했습니다.
java_enthu

죄송합니다, 나는 그것을 출력 확인, 일하고, ..., 내가 다시 테스트 한 bizy했다 paste.ubuntu.com/6002711
라훌 파틸

이것은 사소한 일을하고 있다면 지금까지 가장 우아한 대답입니다. 시간 내 주셔서 감사합니다.
Jerry Andrews

10

GNU Parallel에는 --retries다음 이 있습니다 .

parallel --retries 5 --delay 15s ::: ./do_thing.sh

5

여기 내가 좋아하는 한 줄 별칭 / 스크립트가 있습니다.

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

그런 다음 다음과 같은 작업을 수행 할 수 있습니다.

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

"Next Process"를 찾을 때까지 이전 명령을 계속 실행합니다.


1
zsh에서는 fc -e "#"대신 사용하십시오 fc -s.
Ricardo Stuven

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

이 버전은 명령이 마지막으로 실패한 후 잠들지 않는 이점이 있습니다.
Alexander

1

아래 예를 참조하십시오.

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

done

localhost에서 포트 3389를 연결하려고하는데 5 번 실패 할 때까지 재 시도합니다. 성공하면 루프가 끊어집니다.

$? 0이 아닌 경우 명령이 성공적으로 실행되면 명령 상태가 존재하고, 0이 아닌 경우 명령이 실패하면 명령 상태가 존재 함

약간 복잡해 보입니다. 누군가 이것보다 더 잘할 수 있습니다.


감사합니다 rahul .. 스크립트를 실행하기 위해 다시 시도해야합니까 ??
Sandeep Singh

지금 확인하세요, 업데이트되었습니다
Rahul Patil

$?0이 아닌 경우 명령이 성공적으로 실행되면 명령 상태가 존재합니다. 0이 아닌 경우 명령이 실패하면
Rahul Patil

호스트 및 포트 주소를 제공해야합니다. 스크립트 위치를 dir 만 지정하면됩니다.
Sandeep Singh

종료 상태 코드 $를 제공하는 명령으로 바꾸시겠습니까?
Rahul Patil

1

당신은 사용 loop가능한 명령을, 여기 과 같이 :

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

성공할 때까지 최대 5 번 15 초마다 수행합니다.


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 = "echo blah blah"... 행 10 : [: blah : 정수 표현식이 예상 됨 ... 파이프 등에서는 작동하지 않습니다.
Mercury00
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.