실행이 제한되도록 명령을 래핑하는 방법(예: X분마다 최대 한 번 실행)

실행이 제한되도록 명령을 래핑하는 방법(예: X분마다 최대 한 번 실행)

기본적으로 lodash와 동일한 기능으로 X 기간마다 최대 한 번 실행되도록 명령을 래핑하는 데 관심이 있습니다.throttle기능. 나는 기본적으로 이것을 실행할 수 있기를 원합니다.

throttle 60 -- check-something
another-command
throttle 60 -- check-something
another-command
throttle 60 -- check-something

이러한 각 명령에 대해 throttle(성공적으로) 실행된 후 60초 미만이 경과하면 명령을 건너뜁니다. check-something이와 같은 것이 이미 존재합니까? 쉘스크립트로 하면 쉽나요?

답변1

나는 기본적으로 아무것도 모르지만 래퍼 기능이 작업을 수행할 것입니다. 연관 배열을 사용하여 bash에서 하나를 구현했습니다.

declare -A _throttled=()

throttle() {
  if [ "$#" -lt 2 ]
  then
    printf '%s\n' "Usage: throttle timeout command [arg ... ]" >&2
    return 1
  fi

  local t=$1
  shift

  if [ -n "${_throttled["$1"]}" ]
  then
        if [ "$(date +%s)" -ge "${_throttled["$1"]}" ]
        then
                "$@" && _throttled["$1"]=$((t + $(date +%s)))
        else
                : printf '%s\n' "Timeout for: $1 has not yet been reached" >&2
        fi
  else
        "$@" && _throttled["$1"]=$((t + $(date +%s)))
  fi
}

기본 논리는 다음과 같습니다. 명령에 배열에 항목이 있는 경우 _throttle배열 값과 비교하여 현재 시간을 확인하고, 시간 초과가 만료된 경우 명령을 실행하고 (명령이 성공하면) 새 시간 초과 값을 설정합니다. 제한 시간이 만료되지 않은 경우 정보 메시지를 인쇄하지 마십시오. 반면에 명령이 아직 배열에 항목이 없으면 명령이 실행되고 (명령이 성공하면) 새 시간 초과 값이 설정됩니다.

래퍼 함수는 인수에 따라 명령을 구별하지 않으므로 throttle 30 ls와 동일하지 않습니다 . 이는 배열 참조 및 할당을 throttle 30 ls /tmp로 대체하여 "$1"쉽게 변경할 수 있습니다 "$@".

--또한 예제 구문에서 이를 제거했습니다.

또한 이는 두 번째 해상도로 제한됩니다.

Bash 버전 4.2 이상이면 내장 date함수를 사용하여 외부 명령에 대한 호출을 저장할 수 있습니다.printf

...
_throttled["$1"]=$((t + $(printf '%(%s)T\n' -1)))
...

...현재 시간을 초( ) (%s)단위로 명시적으로 표현 해야 합니다.-1

또는 bash버전 5.0 이상에서는:

_throttled["$1"]=$((t + EPOCHSECONDS))

답변2

그리고 zsh:

typeset -A last_run
zmodload zsh/datetime

throttle() {
  local delay=$1; shift

  # $cmd is the (minimally) quoted arguments of the command joined
  # with spaces and used as the key for the `$last_run` associative array
  local cmd="${(j: :)${(q+)@}}"
  local now=$EPOCHREALTIME
  local lr=$last_run[$cmd]
  local t=$((now - lr))

  if ((t < delay)); then
    printf >&2 '%s was already run successfully %.3g seconds ago\n' "$cmd" "$t"
    return 1
  else
    "$@" && last_run[$cmd]=$now
    # $now being the time when the command started, replace with
    # $EPOCHREALTIME if you want the time it finished.
  fi
}

throttle 3.5 echo "test 1 2 3"
sleep 2
throttle 3.5 echo "test 1 2 3"
sleep 4
throttle 3.5 echo "test 1 2 3"

throttle주어진 명령의 모든 인스턴스가 동일한 쉘 프로세스 내에서(하위 쉘이 아닌) 실행된다고 가정합니다 .

관련 정보