Usando inotifywait junto com vim

14

Eu tenho um script simples que monitora o arquivo para alterações e o sincroniza com cópia remota:

#!/bin/bash

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

Funciona muito bem com o nano, mas falha com o vim. Quando eu uso o nano, ele gera:

somefile CLOSE_WRITE,CLOSE   

e inicia o próximo loop aguardando outra edição.

Quando uso o vim, não há saída, o script é fechado com o código de saída 0.

Eu fiz algumas pesquisas e descobri que close_write é o parâmetro certo para usar o initofywait junto com o vim (primeiro eu queria usar o evento de modificação), mas, por algum motivo, ele falhou para mim.

adam767667
fonte
Funciona para mim. Você alterou o arquivo no vim antes de salvá-lo, em vez de apenas abri-lo para edição?
roaima 8/03
@roaima Só funciona se a backupcopyopção estiver desativada.
Gilles 'SO- stop be evil'

Respostas:

15

Os editores podem seguir várias estratégias para salvar um arquivo. As duas principais variantes são substituir o arquivo existente ou gravar em um novo arquivo e movê-lo no lugar. Gravar em um novo arquivo e movê-lo no lugar tem a propriedade legal de que, a qualquer momento, a leitura do arquivo fornece uma versão completa do arquivo (um instante, o antigo, o próximo, o novo). Se o arquivo for sobrescrito no local, haverá um período incompleto, o que é problemático se algum outro programa acessá-lo naquele momento ou se o sistema travar.

Aparentemente, o Nano substitui o arquivo existente. Seu script detecta o ponto quando termina de escrever (o close_writeevento) e é executado rsyncnesse ponto. Observe que é possível que o rsync pegue uma versão incompleta do arquivo, se você salvar duas vezes em rápida sucessão, antes que o rsync conclua seu trabalho desde o primeiro salvamento.

O Vim, por outro lado, usa a estratégia de escrever e mover - algo para o efeito de

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

O que acontece com a versão antiga do arquivo é que ela é excluída no ponto em que a nova versão é movida para o local. Nesse ponto, o inotifywaitcomando retorna, porque o arquivo que foi instruído a assistir não existe mais. (O novo somefileé um arquivo diferente com o mesmo nome.) Se o Vim tivesse sido configurado para criar um arquivo de backup, o que aconteceria seria algo como

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

e inotifywaitagora estaria assistindo o backup.

Para obter mais informações sobre estratégias para salvar arquivos, consulte Como é possível fazer uma atualização ao vivo enquanto um programa está em execução? e Permissões de arquivo e salvamento

Pode-se dizer ao Vim para usar a estratégia de substituição: desative a backupcopyopção ( :set nobackupcopy). Isso é arriscado, como indicado acima.

Para lidar com as duas estratégias de salvamento, observe o diretório e filtre os eventos close_writee .moved_tosomefile

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- parar de ser mau'
fonte
A desvantagem do método proposto aqui é que, quando você escreve vários arquivos "de uma só vez", seus comandos serão executados uma vez para cada arquivo. Estou editando código, para poder modificar um cabeçalho e algumas outras unidades de tradução e :wa. Então minha compilação é executada uma vez para cada arquivo gravado.
Expiação limitada
@LimitedAtonement Esse é um caso de uso muito mais complicado do que o desta questão. Para o seu caso de uso, você precisará esperar um pouco depois que um arquivo for salvo. Os arquivos nunca são realmente modificados "de uma só vez". Se você salvar vários arquivos :wa, obtém sucessivos eventos de inotificação. Você precisaria esperar depois do primeiro para ver se outros estão chegando. Mas você pode usar o código apresentado aqui: a complexidade adicional entraria no .
Gilles 'SO- stop be evil'
@ Gilles eu decidi mais while true; do inotifywait ... [no -m]; make; sleep .1; done;ou menos. Existem algumas dicas, mas cheguei a algo bastante viável.
Expiação limitada