Używanie inotifywait wraz z vimem

14

Mam prosty skrypt, który monitoruje plik pod kątem zmian i rsynchronizuje go za pomocą zdalnej kopii:

#!/bin/bash

while inotifywait -e close_write somefile
do
    rsync somefile [email protected]:./somefile
done

Działa dobrze z nano, ale nie działa z vimem. Kiedy używam nano, wyświetla:

somefile CLOSE_WRITE,CLOSE   

i rozpoczyna następną pętlę, czekając na kolejną edycję.

Kiedy używam vima, nie ma danych wyjściowych, skrypt po prostu zamyka się kodem wyjścia 0.

Zrobiłem trochę badań i odkryłem, że close_write jest właściwym parametrem do korzystania z initofywait wraz z vimem (najpierw chciałem użyć zdarzenia modyfikacji), ale z jakiegoś powodu mi się nie udaje.

adam767667
źródło
Mi to pasuje. Czy zmieniłeś plik w vimie przed jego zapisaniem, a nie tylko otwieraniem go do edycji?
roaima,
@roaima Działa tylko wtedy, gdy backupcopyopcja jest wyłączona.
Gilles „SO- przestań być zły”

Odpowiedzi:

15

Redaktorzy mogą stosować kilka strategii zapisywania pliku. Dwa główne warianty to zastąpienie istniejącego pliku lub zapisanie nowego pliku i przeniesienie go na miejsce. Zapisywanie do nowego pliku i przenoszenie go na miejsce ma przyjemną właściwość, która w dowolnym momencie czytania z pliku daje pełną wersję pliku (jedna chwila stara, druga chwila nowa). Jeśli plik zostanie nadpisany w miejscu, istnieje czas, w którym jest niekompletny, co jest problematyczne, jeśli jakiś inny program uzyskuje do niego dostęp właśnie wtedy lub gdy system ulega awarii.

Nano najwyraźniej nadpisuje istniejący plik. Twój skrypt wykrywa moment, w którym kończy pisanie ( close_writezdarzenie) i uruchamia się rsyncw tym momencie. Zauważ, że rsync może pobrać niepełną wersję pliku, jeśli zapiszesz dwa razy z rzędu, zanim rsync zakończy swoje zadanie od pierwszego zapisu.

Z drugiej strony Vim stosuje strategię zapisu i przeniesienia - coś z tego wynika

echo 'new content' >somefile.new
mv -f somefile.new somefile

Stara wersja pliku zdarza się, że zostaje on usunięty w miejscu, w którym nowa wersja jest przenoszona na miejsce. W tym momencie inotifywaitpolecenie powraca, ponieważ plik, który kazano obejrzeć, już nie istnieje. (Nowy somefileto inny plik o tej samej nazwie.) Gdyby Vim został skonfigurowany do tworzenia pliku kopii zapasowej, to co by się stało, to coś w rodzaju

echo 'new content' >somefile.new
ln somefile somefile.old
mv -f somefile.new somefile

i inotifywaitbędzie teraz oglądać kopię zapasową.

Aby uzyskać więcej informacji na temat strategii zapisywania plików, zobacz Jak można wykonać aktualizację na żywo podczas działania programu? oraz Uprawnienia do plików i zapisywanie

Vimowi można polecić użycie strategii zastępowania: wyłącz backupcopyopcję ( :set nobackupcopy). Jest to ryzykowne, jak wskazano powyżej.

Aby obsłużyć obie strategie zapisu, obejrzyj katalog i filtruj zarówno zdarzenia, jak close_writei moved_tozdarzenia somefile.

inotifywait -m -e close_write,moved_to --format %e/%f . |
while IFS=/ read -r events file; do
  if [ "$file" = "somefile" ]; then
    …
  fi
done
Gilles „SO- przestań być zły”
źródło
Wadą proponowanej tutaj metody jest to, że kiedy piszesz kilka plików „jednocześnie”, twoje polecenia będą uruchamiane raz dla każdego pliku. Edytuję kod, więc mogę zmodyfikować nagłówek i kilka innych jednostek tłumaczeniowych i :wa. Następnie moja kompilacja jest uruchamiana raz dla każdego zapisanego pliku.
Ograniczone Zadośćuczynienie
@LimitedAtonement To znacznie bardziej skomplikowany przypadek użycia niż ten opisany w tym pytaniu. W przypadku użycia musisz poczekać chwilę po zapisaniu jednego pliku. Pliki nigdy nie są tak naprawdę modyfikowane „jednocześnie”. Jeśli zapiszesz wiele plików :wa, otrzymasz kolejne zdarzenia inotify. Musisz poczekać po pierwszym, aby zobaczyć, czy nadchodzą inni. Ale możesz użyć kodu przedstawionego tutaj: dodatkowa złożoność przejdzie do wewnątrz .
Gilles „SO- przestań być zły”
@Gilles zdecydowałem się na while true; do inotifywait ... [no -m]; make; sleep .1; done;mniej więcej tak. Jest kilka problemów, ale doszedłem do czegoś całkiem wykonalnego.
Ograniczone Zadośćuczynienie