如何中断或消除 inotifywait 循环?

Posted

技术标签:

【中文标题】如何中断或消除 inotifywait 循环?【英文标题】:How can I interrupt or debounce an inotifywait loop? 【发布时间】:2015-03-27 13:31:35 【问题描述】:

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

考虑以下示例:

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

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

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

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

    Debounce 等待处理的事件列表,这样如果五个事件同时发生(或在它已经处理时),它只会再次运行一次。

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

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

【问题讨论】:

【参考方案1】:

要中断,您可以转移事物,以便处理在后台子 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

【讨论】:

这看起来是您尝试做的一个很好的解决方案。【参考方案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 才会重新加载。

【讨论】:

【参考方案3】:

我编写了这个解决方案,只有在安装了 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

说明:这里我们将上次运行日期时间设置为现在,并且仅当上次运行日期时间

例子:

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

【讨论】:

不错,但为什么不避免使用小数呢?

以上是关于如何中断或消除 inotifywait 循环?的主要内容,如果未能解决你的问题,请参考以下文章

如何连续运行 inotifywait 并将其作为 cron 或守护进程运行?

inotifywait 未在 bash 脚本中执行 while 循环

在 Kotlin 中的功能循环中,如何“中断”或“继续”?

抑制或防止重复的 inotifywait 事件?

R:中断循环

如何使用 inotifywait 监视文件夹而不是文件夹中的文件