(完了するには:ストーリー。私がこのような質問をした理由を知りたくない場合は、この記事を読む必要はありません。:カメラモーション検知(「モーション」と呼ばれる)機能を備えたウェブカメラデビルアプリがあります。悪魔は、カメラが動きを検出すると、カスタムコマンドを実行することができます。また、Android携帯にプッシュ通知を簡単に送信できる小さなコマンドラインプログラムもインストールしました。動きが検出されたら、このプッシュメッセージコマンドを実行するようにcam-demonを設定しました。 )
問題:悪魔は、モーションのために撮影するすべてのフレームでカスタムコマンドを実行し、連続モーションが5秒(カメラのフレームレートが10に設定されている)の場合、1秒あたりに多くのプッシュ通知の写真を受け取ります。 1秒あたり10個のプッシュメッセージを受信します。これは操作と見なされます。)
このpush-msgコマンドが最後のx秒/分以内に実行された場合、このコマンドをブロックするにはスクリプトまたはプログラムが必要です。
私は次のことを想像できます:
$ proxy_command.sh --block_time=10s --command==androidpush -msg "There was a motion in your flat!"
この問題を解決する簡単でエレガントな方法が見つかりません(タイムスタンプ付きのファイルを作成してからそのファイルの内容を確認せず)。同様の問題がある人も見つかりません。
上記の問題をできるだけ簡単に解決できる一種のコマンドエージェントや何かがありますか?
答え1
最後の通話時間をファイルの最後の変更時刻として保存
perl
#! /usr/bin/perl
# usage: cmd file seconds cmd args
$file = shift @ARGV;
$time = shift @ARGV;
$age = -M $file;
exit 3 if defined($age) && 86400 * $age < $time;
open $fh, ">>", $file ||
die "Can't open $file: $!\n";
utime undef, undef, $fh;
exec @ARGV;
使用方法:
that-script /some/file 10 androidpush -msg 'There was a motion in your flat!'
最後に実行された時刻を最後の変更時刻として記録し、ファイルが指定された/some/file
時刻より古い場合、コマンドは実行されません。
シェル
BSDまたはGNUを使用すると、find
次のことができます。
#! /bin/sh -
file=${1?} time=${2?}
shift 2
[ "$(find -- "$file" -prune -newermt "$time ago")" ] && exit 3
touch -- "$file"
exec "$@"
次に実行:
that-script /some/file 10sec androidpush -msg 'There was a motion in your flat!'
それにもかかわらず、次の実行のために保持されるように、最後の実行の情報をどこかに保存する必要があります。ファイルシステムは明らかな場所です。あなた自身のためにいくつかの領域を維持することができます。
特定の名前の睡眠プロセス
別の名前空間は次のとおりです。
#! /bin/bash -
label=$0-$(logname)@${1?} time=${2?}
shift 2
pgrep -f "^$label" > /dev/null 2>&1 && exit 3
(exec -a "$label" sleep "$time") &
exec "$@"
次のように使用されます。
that-script motion 10 androidpush -msg 'There was a motion in your flat!'
(sleep
実装がそれを気にしないと仮定argv[0]
)。
bash
私たちは代わりにsh
それを使用していますexec -a arg0
。ない場合、サポートされている他のbash
シェルには、、ksh93
およびmksh
が含まれます。または再開できます。yash
zsh
perl
この名前空間は予約されていません。他のユーザーが同じ名前のプロセスを作成するのを防ぐ方法はありませんが(~/.lastrun
ファイルベースのアプローチでファイルを使用するのとは対照的に)、これらのスクリプトがすべてmotion
同じプロセスによって開始されることを考えると、検索を制限できます。同じ親プロセスIDプロセス:
すべてのスクリプトが常に同じプロセスによって開始される改善されたケース
#! /bin/bash -
label=$0-${1?} time=${2?}
shift 2
pgrep -P "$PPID" -f "^$label" > /dev/null 2>&1 && exit 3
(exec -a "$label" sleep "$time") &
exec "$@"
Linuxのみ:タイムアウト付きのカーネルキーの使用
Linuxでは、ユーザーセッションキーリングのキーを使用することもできます。これは実際にはこのために設計されていませんが、時間が経ってもキーが保持され、タイムアウトを設定できるため、ここでは便利です。
#! /bin/sh -
key=$0-${1?} time=${2?}
shift 2
keyctl search @us user "$key" > /dev/null 2>&1 && exit 3
key=$(keyctl add user "$key" x @us) || exit
keyctl timeout "$key" "$time" || exit
exec "$@"
同時に2つのスクリプトインスタンスが実行されないため、お客様の場合は問題になりませんが、これらすべてに競合状態があり、両方のインスタンスが指定された時間内に実行されないという保証はありません。時間。両方のインスタンスが同時に実行されている場合は、両方のインスタンスのいずれかが条件をリセットする前に条件が正常であることを確認できます。
競合状態を避けるためにファイルをロックする
この問題を解決する1つの方法は、sleep
プロセスがファイルをロックすることです。
#! /bin/sh -
file=${1?} time=${2?}
shift 2
{
flock -n 3 || exit 3
sleep "$time" 3>&3 &
exec "$@"
} 3<> "$file"
(sleep
実行中のコマンドとコマンドの両方がロックを維持するため、コマンドよりも時間がかかる場合でも、コマンドの2つのインスタンスが同時に実行されないようにします。sleep
)