Сделать inotifywait группировать несколько файловых обновлений в один?

У меня есть папка с документами Sphinx, с которой я смотрю inotifywait (от inotify-tools). Скрипт перестраивает html & singlehtml и обновляет Chrome.

#!/bin/sh
inotifywait -mr source --exclude _build -e close_write -e create -e delete -e move | while read file event; do
    make html singlehtml
    xdotool search --name Chromium key --window %@ F5
done

Это прекрасно работает, когда я сохраняю один файл. Тем не менее, когда я hg update в старую ревизию или вставьте несколько файлов в source папка, он запускает скрипт для каждого файла.

Есть ли простой обходной путь (без написания пользовательских сценариев Python - это я могу сделать), чтобы заставить его подождать долю секунды перед запуском сценария?

2 ответа

Решение

Я сделал немного более сложный сценарий оболочки и разместил его в статье:

inotifywait -mr source --exclude _build -e close_write -e create -e delete -e move --format '%w %e %T' --timefmt '%H%M%S' | while read file event tm; do
    current=$(date +'%H%M%S')
    delta=`expr $current - $tm`
    if [ $delta -lt 2 -a $delta -gt -2 ] ; then
        sleep 1  # sleep 1 set to let file operations end
        make html singlehtml
        xdotool search --name Chromium key --window %@ F5
    fi
done

Это делает журнал inotifywait не только имя файла и действия, но и отметку времени. Сценарий сравнивает метку времени с текущим временем unixtime и, если дельта меньше 2 секунд, он запускается make html, Но перед этим он спит 1 секунду, чтобы завершить операции с файлами. Для следующих измененных файлов временная метка будет старой, дельта будет более 2 секунд, и ничего не будет сделано.

Я обнаружил, что этот способ потребляет меньше всего ресурсов процессора и является наиболее надежным.

Я также попытался запустить простой скрипт на Python, но это означало, что если я вставил в папку что-то такое большое, как jQueryUI, тысячи процессов были запущены, а затем превратились в зомби.

Попробуй это:

last_update=0
inotifywait -mr source --exclude _build -e close_write -e create \
    -e delete -e move --format '%T' --timefmt '%s' |
    while read timestamp; do
        if test $timestamp -ge $last_update; then
            sleep 1
            last_update=$(date +%s)
            make html singlehtml
            xdotool search --name Chromium key --window %@ F5
        fi
    done
  1. --format '%T' --timefmt '%s' заставляет метку времени выводиться для каждого события.
  2. test $timestamp -ge $last_update сравнивает метку времени события с меткой времени последнего обновления. Любые события, которые произошли во время сна, таким образом, пропускаются.
  3. sleep 1 добавлено для ожидания накопления событий. Более короткая продолжительность может быть хорошей, например, sleep 0.5, но это было бы менее переносимым.
  4. last_update=$(date +%s%N) устанавливает метку времени последнего обновления, которое будет сравниваться с меткой времени следующего события. Таким образом, любые дополнительные события, которые происходят во время sleep 1 отбрасываются во время следующей итерации цикла.

Обратите внимание, что здесь есть условие гонки, потому что strftime() не поддерживает наносекунды. Этот пример может работать make дважды, если группа событий пересекает вторую границу. Чтобы вместо этого рискнуть пропустить события, заменить -ge с -gt,

Другие вопросы по тегам