10

我有一个小脚本,可以使用inotifywait. 当某些事情发生变化时,一批文件会通过一个大约需要十秒钟运行的过程(编译、压缩、重组等)发送。

考虑以下示例:

touch oli-test
inotifywait -mq oli-test | while read EV; do sleep 5; echo "$EV"; done

如果您touch oli-test在另一个终端中运行几次,您会看到每个循环在继续之前完成。那个场景对我来说非常真实。如果我在文件正在处理时忘记保存文件,或者发现错误,事件会堆积起来,我正在等待几分钟。

令我震惊的是,有两种技术可以客观地使这个工作流程变得更好。我不确定什么是最简单或最好的,所以我将两者都介绍:

  1. 中断之前的运行,并立即重新启动。脚本化过程目前只是一组内联命令。我可以将它们分解为 Bash 函数,我并不热衷于将它们分解得更远。

  2. 对等待处理的事物列表进行去抖动处理,以便如果同时发生五个事件(或在它已经在处理时),它只会再次运行一次。

(或者两者都......因为我确信在某些情况下两者都会有用)

我也对不同的方法持开放态度,inotifywait但它们需要给我相同的结果并在 Ubuntu 上工作。

4

3 回答 3

7

要中断,您可以改变事情,以便处理在后台子shell中运行,并且每个新inotifywait事件都会破坏后台进程:

inotifywait -mq oli-test | while read EV; do
    jobs -p | xargs kill -9
    (
        # do expensive things here
        sleep 5  # a placeholder for compiling
        echo "$EV"
    ) &
done
于 2015-01-28T15:53:00.963 回答
2

这是一个紧凑的解决方案:

inotifywait -q -m -e modify -e create -e close_write --format "%w%f" /etc/nginx/ |\
while read -r path; do
    echo $path changed
    echo "Skipping $(timeout 3 cat | wc -l) further changes"
    service nginx reload
done

第一个read等待一行数据,所以这不会吃掉你的 CPU。timeout 3 cat读取接下来 3 秒内出现的任何进一步更改通知。只有这样才会nginx重新加载。

于 2021-11-12T16:08:26.597 回答
0

我编写了这个解决方案,只有在安装了 bc(计算器)应用程序后才能工作,因为 bash 无法处理浮点数。

lastRunTime=$(date +'%H%M%S.%N')

inotifywait -mr ./web -e create -e delete -e modify | while read file event tm; do

    currentTime=$(date +'%H%M%S.%N')
    delta=$(bc <<< "$lastRunTime - $currentTime")
    echo "$currentTime, $lastRunTime, $delta"

    if (( $(echo "$delta < -1.0" | bc -l) )); then
        echo "run"
        lastRunTime=$(date +'%H%M%S.%N')
    fi

done

说明:这里我们将上次运行日期时间设置为现在,并且仅当上次运行日期时间 < delta(在我的情况下为 -1.0)时才允许下次运行。

例子:

Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.
120845.009293691, 120842.581019388, -2.428274303
run
120845.018643243, 120845.017585539, -.001057704
120845.026360234, 120845.017585539, -.008774695

于 2019-06-19T09:17:05.763 回答