Chcę szybkiego i prostego sposobu wykonania polecenia przy każdej zmianie pliku. Chcę czegoś bardzo prostego, czegoś, co zostawię uruchomionego na terminalu i zamknę go, gdy skończę pracę z tym plikiem.
Obecnie używam tego:
while read; do ./myfile.py ; done
A potem muszę iść do tego terminala i naciskać Enter, ilekroć zapiszę ten plik w moim edytorze. Chcę czegoś takiego:
while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done
Lub każde inne rozwiązanie tak proste.
BTW: Używam Vima i wiem, że mogę dodać komendę automatyczną, aby uruchomić coś na BufWrite, ale nie jest to rozwiązanie, którego chcę teraz.
Aktualizacja: Chcę coś prostego, jeśli to możliwe, można je odrzucić. Co więcej, chcę, aby coś działało w terminalu, ponieważ chcę zobaczyć wyjście programu (chcę zobaczyć komunikaty o błędach).
O odpowiedziach: Dziękujemy za wszystkie odpowiedzi! Wszystkie są bardzo dobre i każde z nich ma inne podejście niż inne. Ponieważ muszę zaakceptować tylko jeden, akceptuję ten, którego faktycznie użyłem (był prosty, szybki i łatwy do zapamiętania), mimo że wiem, że nie jest on najbardziej elegancki.
Odpowiedzi:
Proste, używając inotifywait (zainstaluj
inotify-tools
pakiet swojej dystrybucji ):lub
Pierwszy fragment kodu jest prostszy, ale ma znaczącą wadę: będzie pomijał zmiany dokonane, gdy
inotifywait
nie jest uruchomiony (w szczególności podczasmyfile
działania). Drugi fragment nie ma tej wady. Należy jednak pamiętać, że zakłada, że nazwa pliku nie zawiera spacji. Jeśli to jest problem, użyj--format
opcji, aby zmienić wyjście tak, aby nie zawierało nazwy pliku:Tak czy inaczej, istnieje ograniczenie: jeśli jakiś program zastąpi
myfile.py
innym plikiem, zamiast zapisywać w istniejącymmyfile
,inotifywait
umrze. Wielu redaktorów działa w ten sposób.Aby obejść to ograniczenie, użyj
inotifywait
w katalogu:Alternatywnie, użyj innego narzędzia, które korzysta z tej samej podstawowej funkcji, takiego jak incron (pozwala rejestrować zdarzenia, gdy plik jest modyfikowany) lub fswatch (narzędzie, które działa również na wielu innych wariantach Uniksa, wykorzystując analogię każdego wariantu inotify Linuksa).
źródło
sleep_until_modified.sh
skrypcie, dostępnym na stronie: bitbucket.org/denilsonsa/small_scripts/srcwhile sleep_until_modified.sh derivation.tex ; do latexmk -pdf derivation.tex ; done
jest fantastyczna. Dziękuję Ci.inotifywait -e delete_self
wydaje się działać dobrze dla mnie.while inotifywait -e close_write myfile.py; do ./myfile.py; done
zawsze kończy działanie bez uruchamiania polecenia (bash i zsh). Aby to zadziałało, musiałem dodać|| true
, np .:while inotifywait -e close_write myfile.py || true; do ./myfile.py; done
entr ( http://entrproject.org/ ) zapewnia bardziej przyjazny interfejs do inotify (a także obsługuje * BSD i Mac OS X).
Ułatwia to określenie wielu plików do oglądania (ograniczone tylko przez
ulimit -n
), eliminuje problemy związane z zastępowaniem plików i wymaga mniejszej składni bash:Używałem go w całym drzewie źródeł projektu, aby przeprowadzać testy jednostkowe kodu, który obecnie modyfikuję, i to już znacznie poprawiło mój przepływ pracy.
Flagi takie jak
-c
(wyczyść ekran między uruchomieniami) i-d
(zakończ, gdy nowy plik zostanie dodany do monitorowanego katalogu) zapewniają jeszcze większą elastyczność, na przykład możesz:Od początku 2018 r. Wciąż jest w fazie rozwoju i można go znaleźć w Debian & Ubuntu (
apt install entr
); w każdym razie budowanie z repozytorium autora było bezbolesne.źródło
-d
flagę; jest nieco bardziej skomplikowany, ale możeszwhile sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done
poradzić sobie z nowymi plikami.brew install entr
będzie działać zgodnie z oczekiwaniamiNapisałem program w języku Python, który robi dokładnie to, co nazywa się po zmianie .
Użycie jest proste:
Lub obejrzeć wiele plików:
FILE
może być katalogiem. Oglądaj rekurencyjnie za pomocą-r
. Służy%f
do przekazania nazwy pliku do polecenia.źródło
when-changed FILE 'clear; COMMAND'
.when-changed
jest teraz wieloplatformowy! Sprawdź najnowszą 0.3.0 zwalniającą :)Co powiesz na ten skrypt? Używa
stat
polecenia, aby uzyskać czas dostępu do pliku i uruchamia polecenie, gdy nastąpi zmiana czasu dostępu (przy każdym dostępie do pliku).źródło
stat
zmodyfikowanie czasu byłoby lepszą odpowiedzią „za każdym razem, gdy plik się zmienia”?vmstat -d
obserwowałem dostęp do dysku. Wygląda na to, że Linux wykonuje fantastyczną robotę w buforowaniu tego rodzaju rzeczy: DRozwiązanie wykorzystujące Vima:
Ale nie chcę tego rozwiązania, ponieważ jest trochę denerwujące w pisaniu, trudno jest dokładnie zapamiętać, co dokładnie wpisać, i trochę trudno jest cofnąć jego efekty (trzeba uruchomić
:au! BufWritePost myfile.py
). Ponadto to rozwiązanie blokuje Vima, dopóki polecenie nie zakończy wykonywania.Dodałem tutaj to rozwiązanie tylko dla kompletności, ponieważ może pomóc innym ludziom.
Aby wyświetlić dane wyjściowe programu (i całkowicie zakłócić proces edycji, ponieważ dane wyjściowe będą zapisywane w edytorze przez kilka sekund, dopóki nie naciśniesz Enter), usuń
:silent
polecenie.źródło
entr
(patrz poniżej) - po prostu spraw, aby vim dotknął fikcyjnego pliku, który entr ogląda, i niech entr zrobi resztę w tle ... lubtmux send-keys
jeśli zdarzy ci się być w takim środowisku :).vimrc
plikuJeśli zdarzyło Ci się mieć
npm
zainstalowany,nodemon
jest to prawdopodobnie najłatwiejszy sposób na rozpoczęcie pracy, szczególnie w OS X, który najwyraźniej nie ma narzędzi do inotify. Obsługuje uruchamianie polecenia, gdy zmienia się folder.źródło
nodemon -x "bundle exec rspec" spec/models/model_spec.rb -w app/models -w spec/models
WatchPaths
kluczem, jak pokazano w moim łączu.Dla tych, którzy nie mogą zainstalować
inotify-tools
jak ja, powinno to być przydatne:watch -d -t -g ls -lR
To polecenie zakończy działanie po zmianie danych wyjściowych,
ls -lR
wyświetli listę wszystkich plików i katalogów wraz z ich rozmiarem i datami, więc jeśli plik zostanie zmieniony, powinien zakończyć polecenie, jak mówi mężczyzna:Wiem, że nikt nie może przeczytać tej odpowiedzi, ale mam nadzieję, że ktoś do niej sięgnie.
Przykład wiersza poleceń:
Otwórz inny terminal:
Teraz pierwszy terminal wyjdzie
1,2,3
Prosty przykład skryptu:
źródło
watch -d -t -g "ls -lR tmp | sha1sum"
watch from procps-ng 3.3.10
) akceptuje liczby zmiennoprzecinkowe dla tego przedziału, dlategowatch -n0.2 ...
będzie sondować co piąta sekundę. Dobre dla tych zdrowych testów jednostkowych poniżej milisekundy.rerun2
( na github ) to 10-liniowy skrypt Bash w formie:Zapisz wersję github jako „uruchom ponownie” na swojej ŚCIEŻCE i wywołaj ją, używając:
Uruchamia POLECENIE za każdym razem, gdy w bieżącym katalogu znajduje się zdarzenie modyfikacji systemu plików (rekurencyjne).
Co może się w tym spodobać:
Rzeczy, których można by nie lubić:
Jest to udoskonalenie odpowiedzi @'egoioi.
źródło
"$@"
zamiast$@
, aby poprawnie pracować z argumentami zawierającymi spacje. Ale jednocześnie używaszeval
, co zmusza użytkownika do ponownego uruchomienia, aby zachowywał szczególną ostrożność podczas cytowania.rerun 'command'
. Są po prostu mówiąc, że jeśli kiedyś „$ @”, wówczas użytkownik może powołać jakorerun command
że nie wydaje się przydatne dla mnie (bez cudzysłowów): Ja w ogóle nie chcą Bash zrobić żadnego przetwarzania polecenia przed przekazaniem go uruchomić ponownie. np. jeśli polecenie zawiera „echo $ myvar”, to chcę zobaczyć nowe wartości myvar w każdej iteracji.rerun foo "Some File"
może się zepsuć. Ale ponieważ używaszeval
, możesz go przepisać jakorerun 'foo "Some File"
. Zauważ, że czasami rozszerzenie ścieżki może wprowadzić spacje:rerun touch *.foo
prawdopodobnie się zepsuje, a użyciererun 'touch *.foo'
ma nieco inną semantykę (rozszerzenie ścieżki dzieje się tylko raz lub wiele razy).rerun ls "some file"
psuje się z powodu spacji.rerun touch *.foo*
zwykle działa dobrze, ale kończy się niepowodzeniem, jeśli nazwy plików pasujące do * .foo zawierają spacje. Dzięki, że pomogłeś mi zobaczyć, jakrerun 'touch *.foo'
różni się semantyka, ale podejrzewam, że wersja z pojedynczymi cudzysłowami jest semantyczna, której chcę: chcę, aby każda iteracja powtórzenia działała tak, jakbym ponownie wpisała polecenie - dlatego chcę*.foo
być rozwijana z każdą iteracją . Spróbuję twoich sugestii, aby zbadać ich skutki ...Oto prosty skrypt powłoki Bourne'a, który:
Czyści po sobie po naciśnięciu Ctr-C
Działa to na FreeBSD. Jedynym problemem związanym z przenośnością, jaki mogę wymyślić, jest to, że jakiś inny Uniks nie ma komendy mktemp (1), ale w takim przypadku możesz po prostu na stałe wpisać nazwę pliku tymczasowego.
źródło
$cmd
, ale na szczęście można to łatwo naprawić: porzućcmd
zmienną i wykonaj"$@"
. Twój skrypt nie nadaje się do monitorowania dużego pliku, ale można go naprawić, zastępująccp
gotouch -r
(potrzebujesz tylko daty, a nie zawartości). Jeśli chodzi o przenośność,-nt
test wymaga bash, ksh lub zsh.Spójrz na incron . Jest podobny do crona, ale używa zdarzeń inotify zamiast czasu.
źródło
Inne rozwiązanie z NodeJs, fsmonitor :
zainstalować
Z wiersza poleceń (na przykład monitoruj dzienniki i „sprzedaż detaliczną”, jeśli zmieni się jeden plik dziennika)
źródło
tail -F -q *.log
myślę, że przykład można rozwiązać .tail -f
nieclear
terminal.Zajrzyj do Guard, w szczególności za pomocą tej wtyczki:
https://github.com/hawx/guard-shell
Możesz go skonfigurować tak, aby obserwował dowolną liczbę wzorców w katalogu twojego projektu i wykonywał polecenia po wystąpieniu zmian. Jest duża szansa, że dostępna jest wtyczka do tego, co próbujesz zrobić w pierwszej kolejności.
źródło
jeśli masz zainstalowany nodemon , możesz to zrobić:
W moim przypadku edytuję html lokalnie i wysyłam go na mój zdalny serwer, gdy plik się zmienia.
źródło
W systemie Linux:
Uruchomi polecenie co 2 sekundy.
Jeśli wykonanie polecenia trwa dłużej niż 2 sekundy, zegarek poczeka, aż zostanie wykonany, zanim wykona to ponownie.
źródło
Watchdog to projekt w języku Python i może być właśnie tym, czego szukasz:
Właśnie napisałem dla niego opakowanie wiersza polecenia
watchdog_exec
:Przykład działa
W przypadku zdarzenia fs dotyczącego plików i folderów w bieżącym katalogu uruchom
echo $src $dst
polecenie, chyba że zdarzenie fs zostanie zmodyfikowane, a następnie uruchompython $src
polecenie.Używając krótkich argumentów i ograniczając się do wykonywania tylko wtedy, gdy zdarzenia dotyczą „ main .py”:
EDYCJA: Właśnie znalazłem, że Watchdog ma oficjalny interfejs CLI
watchmedo
, więc sprawdź to również.źródło
Jeśli twój program generuje jakiś dziennik / dane wyjściowe, możesz utworzyć plik Makefile z regułą dla tego dziennika / danych wyjściowych zależną od skryptu i zrobić coś takiego
Alternatywnie możesz utworzyć fałszywy cel i mieć regułę zarówno wywoływania skryptu, jak i dotykania fałszywego celu (wciąż zależnie od skryptu).
źródło
while sleep 1 ; do something ; done
jest nieco lepszy niżwhile true ; do something ; sleep 1 ; done
. Przynajmniej zatrzymuje się łatwo po naciśnięciu Ctrl + C.swarminglogic napisał skrypt o nazwie watchfile.sh , dostępny również jako GitHub Gist .
źródło
stat
podane nazwy plików, uruchamiamd5sum
dane wyjściowe i ponownie uruchamia podane polecenie, jeśli ta wartość się zmieni. Ponieważ jest to Bash, podejrzewam, że dobrze wykonuje podane polecenie dokładnie tak, jakbyś wpisał je po znaku zachęty Bash. (Dla kontrastu, większość rozwiązań tutaj napisanych w innych językach nie wykona poleceń, które na przykład zawierają aliasy powłoki, takie jakll
)Poprawiono odpowiedź Gillesa .
Ta wersja działa
inotifywait
raz i monitoruje zdarzenia (.eg:)modify
później. Takie, któreinotifywait
nie muszą być ponownie wykonywane przy każdym napotkanym zdarzeniu.Jest szybki i szybki! (nawet podczas rekurencyjnego monitorowania dużego katalogu)
źródło
Trochę więcej po stronie programowania, ale chcesz coś takiego jak inotify . Istnieją implementacje w wielu językach, takie jak jnotify i pyinotify .
Ta biblioteka pozwala monitorować pojedyncze pliki lub całe katalogi i zwraca zdarzenia po wykryciu akcji. Zwrócone informacje obejmują między innymi nazwę pliku, akcję (tworzenie, modyfikację, zmianę nazwy, usuwanie) i ścieżkę do pliku, a także inne przydatne informacje.
źródło
Dla tych z Was, którzy szukają rozwiązania FreeBSD, oto port:
źródło
Podoba mi się prostota tego,
while inotifywait ...; do ...; done
ale ma dwa problemy:do ...;
zostaną pominięteDlatego stworzyłem skrypt pomocnika, który używa inotifywait bez tych ograniczeń: inotifyexec
Sugeruję, abyś umieścił ten skrypt na swojej ścieżce, jak w
~/bin/
. Użycie opisuje się po prostu uruchamiając polecenie.Przykład:
inotifyexec "echo test" -r .
źródło
Ulepszone rozwiązanie Sebastiana z
watch
poleceniem:watch_cmd.sh
:Przykład połączenia:
Działa, ale bądź ostrożny:
watch
komenda zna błędy (patrz man): reaguje na zmiany tylko w WIDOCZNYM w końcowych częściach-g CMD
wyjścia.źródło
Możesz spróbować odruchu .
Reflex to małe narzędzie do oglądania katalogu i ponownego uruchamiania polecenia po zmianie niektórych plików. Jest świetny do automatycznego uruchamiania zadań kompilacji / lint / testowania oraz do ponownego ładowania aplikacji, gdy kod się zmienia.
źródło
Odpowiedź oneliner, której używam do śledzenia zmiany pliku:
Nie musisz inicjować BF, jeśli wiesz, że pierwsza data to godzina rozpoczęcia.
To jest proste i przenośne. Istnieje inna odpowiedź oparta na tej samej strategii przy użyciu skryptu tutaj. Spójrz także.
Użycie: Używam tego do debugowania i pilnowania
~/.kde/share/config/plasma-desktop-appletsrc
; z jakiegoś nieznanego powodu ciągle gubię mojeSwitchTabsOnHover=false
źródło
Używam tego skryptu, aby to zrobić. Używam inotify w trybie monitorowania
Zapisz to jako runatwrite.sh
przy każdym zapisie uruchomi plik myfile.sh.
źródło
Dla tych, którzy używają OS X, możesz użyć LaunchAgent, aby obserwować ścieżkę / plik pod kątem zmian i zrobić coś, kiedy to nastąpi. FYI - LaunchControl to dobra aplikacja do łatwego tworzenia / modyfikowania / usuwania demonów / agentów.
( przykład wzięty stąd )
źródło
Mam do tego GIST, a użycie jest dość proste
https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55
źródło
Dla osób, które Googling znajdują w poszukiwaniu zmian w konkretnym pliku, odpowiedź jest znacznie prostsza (zainspirowana odpowiedzią Gillesa ).
Jeśli chcesz coś zrobić po zapisaniu określonego pliku, oto jak:
Zapisz to, na przykład,
copy_myfile.sh
i umieść.sh
plik w/etc/init.d/
folderze, aby uruchomił się przy starcie.źródło
Narzędzie „fido” może być kolejną opcją dla tej potrzeby. Zobacz https://www.joedog.org/fido-home/
źródło
Jak zrobiło to kilka innych, napisałem również lekkie narzędzie wiersza poleceń, aby to zrobić. Jest w pełni udokumentowany, przetestowany i modułowy.
Watch-Do
Instalacja
Możesz go zainstalować (jeśli masz Python3 i pip), używając:
Stosowanie
Użyj go od razu, uruchamiając:
Przegląd funkcji
-w '*.py'
lub-w '**/*.py'
)-d
ponownie określ flagę)-r
aby to włączyć)źródło