Verwenden Sie inotifywait zusammen mit vim

14

Ich habe ein einfaches Skript, das die Datei auf Änderungen überwacht und sie mit der Remote-Kopie synchronisiert:

#!/bin/bash

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

Es funktioniert gut mit Nano, scheitert aber mit Vim. Wenn ich Nano benutze, gibt es aus:

somefile CLOSE_WRITE,CLOSE   

und startet die nächste Schleife und wartet auf eine weitere Ausgabe.

Wenn ich vim verwende, gibt es keine Ausgabe, Skript schließt nur mit Exit-Code 0.

Ich habe ein paar Nachforschungen angestellt und herausgefunden, dass close_write der richtige Parameter ist, um initofywait zusammen mit vim zu starten (zuerst wollte ich modify event verwenden), aber aus irgendeinem Grund schlägt dies für mich fehl.

adam767667
quelle
Für mich geht das. Sie haben die Datei in vim vor dem Speichern geändert , anstatt sie nur zum Bearbeiten zu öffnen?
Roaima
@roaima Funktioniert nur, wenn die backupcopyOption deaktiviert ist.
Gilles 'SO- hör auf böse zu sein'

Antworten:

14

Editoren können verschiedene Strategien zum Speichern einer Datei anwenden. Die beiden Hauptvarianten bestehen darin, die vorhandene Datei zu überschreiben oder in eine neue Datei zu schreiben und sie an ihren Platz zu verschieben. Das Schreiben in eine neue Datei und das Verschieben an Ort und Stelle hat die nette Eigenschaft, dass Sie beim Lesen aus der Datei zu jedem Zeitpunkt eine vollständige Version der Datei erhalten (ein Augenblick der alte, der nächste Augenblick der neue). Wenn die Datei überschrieben wird, ist sie in einer bestimmten Zeit unvollständig. Dies ist problematisch, wenn gerade ein anderes Programm darauf zugreift oder das System abstürzt.

Nano überschreibt anscheinend die vorhandene Datei. Ihr Skript erkennt den Punkt, an dem es mit dem Schreiben fertig ist (das close_writeEreignis) und wird rsyncan diesem Punkt ausgeführt. Beachten Sie, dass es für rsync möglich ist, eine unvollständige Version der Datei abzurufen, wenn Sie zweimal schnell hintereinander speichern, bevor rsync den Job vom ersten Speichern an abgeschlossen hat.

Auf der anderen Seite verwendet Vim die Write-then-Move-Strategie

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

Was mit der alten Version der Datei passiert, ist, dass sie an dem Punkt gelöscht wird, an dem die neue Version eingefügt wird. Zu diesem Zeitpunkt wird der inotifywaitBefehl zurückgegeben, da die Datei, die überwacht werden soll, nicht mehr vorhanden ist. (Die neue somefileDatei ist eine andere Datei mit demselben Namen.) Wenn Vim so konfiguriert worden wäre, dass eine Sicherungsdatei erstellt wird, würde so etwas passieren

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

und inotifywaitwürde jetzt die Sicherung beobachten.

Weitere Informationen zu Dateispeicherstrategien finden Sie unter Wie kann ein Live-Update durchgeführt werden, während ein Programm ausgeführt wird? und Dateiberechtigungen und Speichern

Vim kann angewiesen werden, die Überschreibstrategie zu verwenden: Deaktivieren Sie die backupcopyOption ( :set nobackupcopy). Dies ist riskant, wie oben angegeben.

Um beide Speicherstrategien zu handhaben, beobachten Sie das Verzeichnis und filtern Sie beide close_writeund moved_toEreignisse nach 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 - hör auf böse zu sein'
quelle
Der Nachteil der hier vorgeschlagenen Methode besteht darin, dass beim gleichzeitigen Schreiben mehrerer Dateien Ihre Befehle für jede Datei einmal ausgeführt werden. Ich bearbeite Code, um einen Header und einige andere Übersetzungseinheiten zu ändern :wa. Dann wird mein Build für jede geschriebene Datei einmal ausgeführt.
Eingeschränktes Sühnopfer
@LimitedAtonement Das ist ein viel komplizierterer Anwendungsfall als der in dieser Frage. Für Ihren Anwendungsfall müssen Sie nach dem Speichern einer Datei etwas warten. Dateien werden nie wirklich "auf einmal" geändert. Wenn Sie mehrere Dateien mit speichern :wa, erhalten Sie aufeinanderfolgende Inotify-Ereignisse. Sie müssen nach dem ersten warten, um zu sehen, ob andere kommen. Sie können jedoch den hier vorgestellten Code verwenden: Die zusätzliche Komplexität würde innerhalb der .
Gilles 'SO- hör auf böse zu sein'
@ Gilles Ich entschied mich für while true; do inotifywait ... [no -m]; make; sleep .1; done;oder so. Es gibt einige Fallstricke, aber ich bin zu etwas gekommen, das sich ganz gut verarbeiten lässt.
Eingeschränktes Sühnopfer