Я хочу быстрый и простой способ выполнить команду при изменении файла. Я хочу что-то очень простое, что-то, что я оставлю работающим на терминале и закрою это всякий раз, когда я закончу работать с этим файлом.
В настоящее время я использую это:
while read; do ./myfile.py ; done
А затем мне нужно перейти к этому терминалу и нажимать Enterвсякий раз, когда я сохраняю этот файл в моем редакторе. Я хочу что-то вроде этого:
while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done
Или любое другое решение, столь же простое.
Кстати: я использую Vim, и я знаю, что могу добавить автокоманду для запуска чего-либо на BufWrite, но сейчас это не то решение, которое мне нужно.
Обновление: я хочу что-то простое, если возможно, отказаться. Более того, я хочу, чтобы что-то запускалось в терминале, потому что я хочу видеть вывод программы (я хочу видеть сообщения об ошибках).
Об ответах: Спасибо за все ваши ответы! Все они очень хороши, и каждый из них отличается от других. Поскольку мне нужно принять только один, я принимаю тот, который я фактически использовал (это было просто, быстро и легко запомнить), хотя я знаю, что это не самый элегантный.
Ответы:
Просто с помощью inotifywait (установите
inotify-tools
пакет вашего дистрибутива ):или же
Первый фрагмент проще, но у него есть существенный недостаток: он пропустит изменения, выполненные, когда
inotifywait
он не запущен (в частности, во времяmyfile
работы). Второй фрагмент не имеет этого дефекта. Однако следует помнить, что предполагается, что имя файла не содержит пробелов. Если это проблема, используйте--format
опцию, чтобы изменить вывод, чтобы не включать имя файла:В любом случае, есть ограничение: если какая-то программа заменит
myfile.py
другой файл, а не записывает в существующийmyfile
,inotifywait
умрет. Многие редакторы работают таким образом.Чтобы преодолеть это ограничение, используйте
inotifywait
в каталоге:В качестве альтернативы используйте другой инструмент, который использует те же базовые функции, например, incron (позволяет регистрировать события при изменении файла) или fswatch (инструмент, который также работает во многих других вариантах Unix с использованием аналога каждого варианта inotify Linux).
источник
sleep_until_modified.sh
сценарии, доступном по адресу: bitbucket.org/denilsonsa/small_scripts/srcwhile sleep_until_modified.sh derivation.tex ; do latexmk -pdf derivation.tex ; done
Это фантастично. Спасибо.inotifywait -e delete_self
кажется, хорошо работает для меня.while inotifywait -e close_write myfile.py; do ./myfile.py; done
всегда выходит без выполнения команды (bash и zsh). Чтобы это работало, мне нужно было добавить|| true
, например:while inotifywait -e close_write myfile.py || true; do ./myfile.py; done
entr ( http://entrproject.org/ ) предоставляет более дружественный интерфейс для inotify (а также поддерживает * BSD и Mac OS X).
Это позволяет очень легко указать несколько файлов для просмотра (ограничено только
ulimit -n
), избавляет от необходимости иметь дело с заменяемыми файлами и требует меньше синтаксиса bash:Я использовал его во всем дереве исходного кода проекта для запуска модульных тестов кода, который я сейчас изменяю, и это уже значительно улучшило мой рабочий процесс.
Флаги типа
-c
(очистка экрана между запусками) и-d
(выход при добавлении нового файла в контролируемый каталог) добавляют еще больше гибкости, например, вы можете сделать следующее:По состоянию на начало 2018 года он все еще находится в активной разработке, и его можно найти в Debian & Ubuntu (
apt install entr
); Строительство из репо автора было в любом случае безболезненным.источник
-d
флаг; это немного более многословно, но вы можете сделать,while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done
чтобы иметь дело с новыми файлами.brew install entr
будет работать как положеноЯ написал программу на Python, чтобы сделать именно это, когда-изменился .
Использование простое:
Или посмотреть несколько файлов:
FILE
может быть каталогом. Смотреть рекурсивно с-r
. Используйте%f
для передачи имени файла команде.источник
when-changed FILE 'clear; COMMAND'
.when-changed
сейчас кроссплатформенный! Ознакомьтесь с последними 0.3.0 релиз :)Как насчет этого сценария? Он использует
stat
команду для получения времени доступа к файлу и запускает команду всякий раз, когда происходит изменение времени доступа (при каждом обращении к файлу).источник
stat
измененное время не будет лучшим ответом «всякий раз, когда файл меняется»?vmstat -d
следил за доступом к диску. Похоже, linuxРешение с использованием Vim:
Но я не хочу, чтобы это решение, потому что это немного раздражает при наборе, немного сложно вспомнить, что именно печатать, и немного сложно отменить его эффекты (нужно запустить
:au! BufWritePost myfile.py
). Кроме того, это решение блокирует Vim до завершения выполнения команды.Я добавил это решение здесь только для полноты, так как оно может помочь другим людям.
Чтобы отобразить вывод программы (и полностью прервать процесс редактирования, поскольку вывод будет записываться в ваш редактор в течение нескольких секунд, пока вы не нажмете Enter), удалите
:silent
команду.источник
entr
(см. Ниже) - просто заставьте vim коснуться фиктивного файла, который просматривает entr, и пусть entr сделает все остальное в фоновом режиме ... или,tmux send-keys
если вы оказались в такой среде :).vimrc
файлаЕсли у вас
npm
установлена программа,nodemon
возможно, это самый простой способ начать работу, особенно в OS X, которая, очевидно, не имеет инструментов inotify. Он поддерживает запуск команды при изменении папки.источник
nodemon -x "bundle exec rspec" spec/models/model_spec.rb -w app/models -w spec/models
WatchPaths
ключом, как показано в моей ссылке.Для тех, кто не может установить
inotify-tools
как я, это должно быть полезно:watch -d -t -g ls -lR
Эта команда завершится при изменении выходных данных,
ls -lR
перечислит каждый файл и каталог с указанием размера и даты, поэтому, если файл будет изменен, он должен выйти из команды, как говорит man:Я знаю, что этот ответ не может быть прочитан никем, но я надеюсь, что кто-то достигнет его.
Пример командной строки:
Откройте другой терминал:
Теперь первый терминал выведет
1,2,3
Простой пример скрипта:
источник
watch -d -t -g "ls -lR tmp | sha1sum"
watch from procps-ng 3.3.10
) принимает значения с плавающей запятой для своего интервала, поэтомуwatch -n0.2 ...
опрашивает каждую пятую секунды. Хорошо для тех здоровых субмиллисекундных юнит-тестов.rerun2
( на github ) представляет собой 10-строчный Bash-скрипт вида:Сохраните версию github как 'rerun' в вашей переменной PATH и вызовите ее, используя:
Он запускает COMMAND каждый раз, когда в вашем текущем каталоге происходит событие изменения файловой системы (рекурсивно.)
Вещи, которые могут понравиться об этом:
Вещи, которые могут не понравиться об этом:
Это уточнение ответа @ cychoi.
источник
"$@"
вместо$@
, чтобы правильно работать с аргументами, содержащими пробелы. Но в то же время вы используетеeval
, что заставляет пользователя перезапуска быть особенно осторожным при цитировании.rerun 'command'
. Вы просто говорите, что если бы я использовал «$ @», то пользователь мог бы вызывать какrerun command
(без кавычек?), Что не кажется мне полезным: я обычно не хочу, чтобы Bash выполнял какую-либо обработку команды перед ее передачей. перезапустить. Например, если команда содержит «echo $ myvar», то я хочу видеть новые значения myvar в каждой итерации.rerun foo "Some File"
может сломаться. Но так как вы используетеeval
, это может быть переписано какrerun 'foo "Some File"
. Обратите внимание, что иногда расширение пути может вводить пробелы:rerun touch *.foo
вероятно, будет нарушено, а использованиеrerun 'touch *.foo'
имеет немного другую семантику (расширение пути происходит только один раз или несколько раз).rerun ls "some file"
ломается из-за пробелов.rerun touch *.foo*
обычно работает нормально, но не работает, если имена файлов, соответствующие * .foo, содержат пробелы. Спасибо за то, что помогли мне понять, каковаrerun 'touch *.foo'
различная семантика, но я подозреваю, что версия с одинарными кавычками - это семантика, которую я хочу: я хочу, чтобы каждая итерация повторения работала так, как будто я набирал команду снова - следовательно, я хочу*.foo
расширяться на каждой итерации , Я попробую ваши предложения, чтобы изучить их последствия ...Вот простой сценарий оболочки Bourne, который:
Убирает за собой при нажатии Ctr-C
Это работает на FreeBSD. Единственная проблема с переносимостью, о которой я могу подумать, это то, что в некоторых других Unix нет команды mktemp (1), но в этом случае вы можете просто жестко закодировать имя временного файла.
источник
$cmd
, у вас возникает серьезная проблема с цитированием , но, к счастью, это легко исправить: отбросьтеcmd
переменную и выполните"$@"
. Ваш скрипт не подходит для мониторинга большого файла, но это можно исправить, заменивcp
наtouch -r
(вам нужна только дата, а не содержимое). Что касается переносимости, для-nt
теста требуется bash, ksh или zsh.Посмотрите на Incron . Это похоже на cron, но использует события inotify вместо времени.
источник
Другое решение с NodeJs, fsmonitor :
устанавливать
Из командной строки (например, монитор журналов и «розничная торговля», если один файл журнала изменяется)
источник
tail -F -q *.log
, я думаю.tail -f
неclear
терминал.Посмотрите на Guard, в частности, с этим плагином:
https://github.com/hawx/guard-shell
Вы можете настроить его на просмотр любого количества шаблонов в каталоге вашего проекта и выполнение команд при возникновении изменений. Хороший шанс, даже если есть плагин для того, что вы пытаетесь сделать в первую очередь.
источник
если у вас установлен nodemon , то вы можете сделать это:
В моем случае я редактирую html локально и отправляю его на мой удаленный сервер при изменении файла.
источник
Под Linux:
Будет запускать команду каждые 2 секунды.
Если ваша команда выполняется более 2 секунд, часы будут ждать, пока она не будет выполнена, прежде чем делать это снова.
источник
Watchdog - это проект Python, и он может быть именно тем, что вы ищете:
Просто написал оболочку для командной строки
watchdog_exec
:Пример работает
На событии fs, включающем файлы и папки в текущем каталоге, выполните
echo $src $dst
команду, если она не изменена, а затем выполнитеpython $src
команду.Использование коротких аргументов и ограничение на выполнение только тогда, когда в событиях используется « main .py»:
РЕДАКТИРОВАТЬ: Только что обнаружил, что Watchdog имеет официальный CLI называется
watchmedo
, так что проверьте это также.источник
Если ваша программа генерирует какой-либо журнал / вывод, вы можете создать Makefile с правилом для этого журнала / вывода, который зависит от вашего сценария и сделать что-то вроде
Кроме того, вы можете создать фальшивую цель и назначить ей правило, и вызвать ваш скрипт, и коснуться фальшивой цели (хотя все еще зависит от вашего скрипта).
источник
while sleep 1 ; do something ; done
немного лучше чемwhile true ; do something ; sleep 1 ; done
. По крайней мере, он легко останавливается при нажатии Ctrl + C.swarminglogic написал скрипт под названием watchfile.sh , также доступный в виде GitHub Gist .
источник
stat
заданные имена файлов, запускаетmd5sum
выходные данные и повторно запускает данную команду, если это значение изменяется. Поскольку это Bash, я подозреваю, что он хорошо выполняет заданную команду точно так же, как если бы вы вводили ее в командной строке Bash. (Напротив, большинство решений, написанных здесь на других языках, не смогут выполнять команды, которые, например, содержат псевдонимы оболочки, такие какll
)Улучшено после ответа Жиля .
Эта версия запускается
inotifywait
один раз и отслеживает события (.eg:)modify
после этого. Такой,inotifywait
который не нужно повторять при каждом обнаруженном событии.Это быстро и быстро! (даже при рекурсивном мониторинге большого каталога)
источник
Еще немного о программировании, но вы хотите что-то вроде inotify . Существуют реализации на многих языках, таких как jnotify и pyinotify .
Эта библиотека позволяет отслеживать отдельные файлы или целые каталоги и возвращает события при обнаружении действия. Возвращаемая информация включает в себя имя файла, действие (создание, изменение, переименование, удаление) и путь к файлу, а также другую полезную информацию.
источник
Для тех из вас, кто ищет решение FreeBSD, вот порт:
источник
Мне нравится простота,
while inotifywait ...; do ...; done
однако у нее есть две проблемы:do ...;
будут пропущеныДля этого я создал вспомогательный скрипт, который использует inotifywait без этих ограничений: inotifyexec
Я предлагаю вам поставить этот скрипт на вашем пути, как в
~/bin/
. Использование описывается просто запуском команды.Пример:
inotifyexec "echo test" -r .
источник
Улучшено решение Себастьяна с помощью
watch
команды:watch_cmd.sh
:Пример звонка:
Это работает, но будьте осторожны:
watch
команда имеет известные ошибки (см. Man): она реагирует на изменения только в VISIBLE в терминальных частях-g CMD
вывода.источник
Вы можете попробовать рефлекс .
Reflex - небольшой инструмент для просмотра каталога и повторного запуска команды при изменении определенных файлов. Он отлично подходит для автоматического запуска задач компиляции / lint / test и для перезагрузки приложения при изменении кода.
источник
Ответ oneliner, который я использую, чтобы отслеживать изменения файла:
Вам не нужно инициализировать BF, если вы знаете, что первая дата является временем начала.
Это просто и портативно. Здесь есть другой ответ, основанный на той же стратегии с использованием сценария. Посмотрите также.
Использование: я использую это для отладки и слежения за
~/.kde/share/config/plasma-desktop-appletsrc
; что по неизвестной причине продолжает терятьSwitchTabsOnHover=false
источник
Я использую этот скрипт, чтобы сделать это. Я использую inotify в режиме монитора
Сохраните это как runatwrite.sh
он будет запускать myfile.sh при каждой записи.
источник
Для тех, кто использует OS X, вы можете использовать LaunchAgent, чтобы отслеживать путь / файл на предмет изменений и что-то делать, когда это происходит. К вашему сведению - LaunchControl - хорошее приложение для простого создания / изменения / удаления демонов / агентов.
( пример взят здесь )
источник
У меня есть GIST для этого, и использование довольно просто
https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55
источник
Для людей, которые находят это в Google для изменений в конкретном файле, ответ намного проще (вдохновлен ответом Жиля ).
Если вы хотите что-то сделать после записи определенного файла, вот как:
Сохраните это как, например,
copy_myfile.sh
и поместите.sh
файл в/etc/init.d/
папку, чтобы запустить его при запуске.источник
Инструмент «fido» может быть еще одним вариантом для этой необходимости. Смотрите https://www.joedog.org/fido-home/
источник
Как и некоторые другие, я также написал для этого облегченный инструмент командной строки. Он полностью документирован, протестирован и модульный.
Часы-Do
Монтаж
Вы можете установить его (если у вас есть Python3 и pip), используя:
использование
Используйте это сразу, запустив:
Обзор возможностей
-w '*.py'
или-w '**/*.py'
)-d
флаг снова)-r
чтобы включить это)источник