如果命令在最近 x 秒/分鐘內執行,則阻止/阻止命令
(只是為了完成:故事;如果您不想知道我為什麼要問這個問題,則無需閱讀此內容:我有一個帶有攝像頭運動檢測的網路攝像頭惡魔應用程序(稱為“運動”)。這個惡魔能夠在相機檢測到運動時觸發自定義命令。此外,我還安裝了一個小型命令行程序,可以輕鬆地將推送通知發送到我的 android 手機。我將 cam-demon 配置為執行該推送消息命令他檢測到一個動作。)
問題:惡魔在他為動作拍攝的每一幀中都會觸發該自定義命令,當有一個連續動作時,我會收到大量的推送通知 - 比如說 - 5 秒(相機幀速率設置為 10圖片/秒,所以我每秒收到 10 個推送消息,這被認為是一個動作)。
如果它已經在過去 x 秒/分鐘內執行,我需要一個腳本或程序來阻止該 push-msg 命令。
我可以想像這樣的事情:
$ proxy_command.sh --block_time=10s --command==androidpush -msg "There was a motion in your flat!"
我找不到一種簡單/優雅的方法來解決這個問題(無需編寫帶有時間戳的文件,然後檢查該文件的內容)。我也找不到有類似問題的人。
是否有某種命令代理或可以盡可能簡單地解決我上面描述的問題的東西?
將上次呼叫時間儲存為文件的最後修改時間
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
的 shell 包括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 "$@"
現在,在您的情況下並不重要,因為您沒有同時執行該腳本的兩個實例,但是所有這些實例都有競爭條件,這使得它不能保證兩個實例不會在規定時間內執行。如果兩個實例同時執行,它們都可以在其中任何一個重置條件之前驗證條件是否正常。
鎖定文件以避免競爭條件
一種可以解決此問題的方法是讓
sleep
程序鎖定文件:#! /bin/sh - file=${1?} time=${2?} shift 2 { flock -n 3 || exit 3 sleep "$time" 3>&3 & exec "$@" } 3<> "$file"
(此外,這裡
sleep
執行的命令和正在執行的命令都將持有鎖,這將確保命令的兩個實例不會同時執行,即使它們的執行時間比sleep
命令長)。