
基本的には、lodashと同じ機能で、X期間ごとに最大1回実行されるようにコマンドをラップすることに興味があります。throttle
機能。私は基本的にこれを実行できるようにしたいです。
throttle 60 -- check-something
another-command
throttle 60 -- check-something
another-command
throttle 60 -- check-something
これらの各コマンドに対してthrottle
(成功的に)実行されてから60秒未満が経過すると、コマンドはスキップされます。check-something
このようなものはすでに存在していますか?シェルスクリプトで簡単にできますか?
答え1
私は基本的に何も知りませんが、ラッパー機能はこれを行います。連想配列を使用してbashで1つを実装しました。
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"
簡単に変更できます"$@"
。
--
また、サンプル構文からこれを削除しました。
さらに、これは第2の解像度に限定される。
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
与えられたコマンドのすべてのインスタンスが同じシェルプロセス内で(サブシェルではなく)実行されるとします。