Utilizzando inotifywait insieme a vim


14

Ho un semplice script che monitora il file per le modifiche e lo sincronizza con la copia remota:

#!/bin/bash

while inotifywait -e close_write somefile
do
    rsync somefile user@host.domain:./somefile
done

Funziona bene con nano, ma fallisce con vim. Quando uso nano, viene visualizzato:

somefile CLOSE_WRITE,CLOSE   

e inizia il ciclo successivo in attesa di un'altra edizione.

Quando uso vim, non c'è output, lo script si chiude con il codice di uscita 0.

Ho fatto qualche ricerca e ho scoperto che close_write è il parametro giusto per usare initofywait insieme a vim (prima volevo usare un evento di modifica), ma per qualche ragione non funziona.


Per me funziona. Hai modificato il file in vim prima di salvarlo, anziché aprirlo per la modifica?
roaima,

@roaima Funziona solo se l' backupcopyopzione è disattivata.
Gilles 'SO- smetti di essere malvagio' il

Risposte:


15

Gli editor possono seguire diverse strategie per salvare un file. Le due varianti principali sono quelle di sovrascrivere il file esistente o di scrivere in un nuovo file e spostarlo in posizione. Scrivere su un nuovo file e spostarlo in posizione ha la bella proprietà che in qualsiasi momento, leggere dal file ti dà una versione completa del file (un istante il vecchio, il prossimo istante il nuovo). Se il file viene sovrascritto sul posto, c'è un tempo durante il quale è incompleto, il che è problematico se qualche altro programma vi accede in quel momento o se il sistema si arresta in modo anomalo.

Apparentemente Nano sovrascrive il file esistente. La tua sceneggiatura rileva il punto in cui ha finito di scrivere (l' close_writeevento) e viene eseguita rsynca quel punto. Si noti che è possibile per rsync acquisire una versione incompleta del file, se si salva due volte in rapida successione, prima che rsync abbia completato il suo lavoro dal primo salvataggio.

Vim, d'altra parte, usa la strategia di scrittura e di spostamento, qualcosa a effetto di

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

Quello che succede alla vecchia versione del file è che viene eliminato nel punto in cui viene spostata la nuova versione. A questo punto, il inotifywaitcomando ritorna, perché il file che gli è stato detto di guardare non esiste più. (Il nuovo somefileè un file diverso con lo stesso nome.) Se Vim fosse stato configurato per creare un file di backup, cosa accadrebbe sarebbe qualcosa di simile

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

e inotifywaitora starebbe guardando il backup.

Per ulteriori informazioni sulle strategie di salvataggio dei file, vedere Come è possibile eseguire un aggiornamento live mentre un programma è in esecuzione? e autorizzazioni e salvataggio dei file

Si può dire a Vim di usare la strategia di sovrascrittura: disattivare l' backupcopyopzione ( :set nobackupcopy). Questo è rischioso, come indicato sopra.

Per gestire entrambe le strategie di salvataggio, guarda la directory e filtra sia gli eventi close_writeche gli moved_toeventi somefile.

inotifywait -m -e close_write,moved_to --format %e/%f . |
while IFS=/ read -r events file; do
  if [ "$file" = "somefile" ]; then
    …
  fi
done

Lo svantaggio del metodo proposto qui è che quando si scrivono più file "contemporaneamente", i comandi verranno eseguiti una volta per ogni file. Sto modificando il codice, quindi posso modificare un'intestazione e un paio di altre unità di traduzione e :wa. Quindi la mia build viene eseguita una volta per ogni file scritto.
Espiazione limitata il

@LimitedAtonement Questo è un caso d'uso molto più complicato di quello in questa domanda. Per il tuo caso d'uso, dovrai attendere un po 'dopo aver salvato un file. I file non vengono mai realmente modificati "in una volta". Se si salvano più file con :wa, si ottengono eventi di inotify successivi. Dovresti aspettare dopo il primo per vedere se gli altri stanno arrivando. Ma puoi usare il codice presentato qui: la complessità aggiuntiva andrebbe dentro .
Gilles 'SO- smetti di essere malvagio' il

@Gilles Ho deciso di while true; do inotifywait ... [no -m]; make; sleep .1; done;farlo. Ci sono alcuni gotcha, ma sono arrivato a qualcosa di abbastanza praticabile.
Espiazione limitata il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.