如何包装命令以使其执行受到限制(即,它最多每 X 分钟执行一次)

如何包装命令以使其执行受到限制(即,它最多每 X 分钟执行一次)

我有兴趣包装一个命令,使其每 X 持续时间最多运行一次;本质上,与 lodash 具有相同的功能throttle功能。我基本上希望能够运行这个:

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

对于其中每个命令,如果自(成功)运行throttle以来不到 60 秒,则将跳过该命令。check-something这样的东西已经存在了吗?用shell脚本做起来容易吗?

答案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 lsthrottle 30 ls /tmp.通过替换"$1"to的数组引用和赋值可以轻松更改这一点"$@"

--另请注意,我从您的示例语法中删除了。

另请注意,这仅限于秒级分辨率。

如果您有 bash 版本 4.2 或更高版本,您可以使用内置date功能来保存对外部命令的调用:printf

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

...我们要求当前时间(%s)明确以秒为单位的时间 ( -1)。

或者在bash5.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在同一个 shell 进程中运行(而不是在子 shell 中)。

相关内容