Menggunakan inotifyunggu bersama dengan vim

14

Saya memiliki skrip sederhana yang memonitor file untuk perubahan dan menyalinnya dengan salinan jarak jauh:

#!/bin/bash

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

Ini berfungsi dengan baik dengan nano, tetapi gagal dengan vim. Ketika saya menggunakan nano, itu menghasilkan:

somefile CLOSE_WRITE,CLOSE   

dan mulai loop berikutnya menunggu edisi lain.

Ketika saya menggunakan vim, tidak ada output, skrip ditutup dengan kode keluar 0.

Saya melakukan riset dan menemukan bahwa close_write adalah parameter yang tepat untuk menggunakan initofywait bersama dengan vim (pertama saya ingin menggunakan memodifikasi acara), namun untuk beberapa alasan gagal bagi saya.

adam767667
sumber
Ini bekerja untuk saya. Anda mengubah file dalam vim sebelum menyimpannya, bukan hanya membukanya untuk diedit?
roaima
@roaima Hanya berfungsi jika backupcopyopsi tidak aktif.
Gilles 'SO- stop being evil'

Jawaban:

15

Editor dapat mengikuti beberapa strategi untuk menyimpan file. Dua varian utama adalah menimpa file yang ada, atau menulis ke file baru dan memindahkannya di tempat. Menulis ke file baru dan memindahkannya di tempat memiliki properti bagus yang setiap saat membaca dari file memberi Anda versi lengkap file (satu instan yang lama, instan berikutnya yang baru). Jika file ditimpa di tempat, ada waktu di mana itu tidak lengkap, yang bermasalah jika beberapa program lain mengaksesnya saat itu atau jika sistem crash.

Nano rupanya menimpa file yang ada. Script Anda mendeteksi titik ketika selesai menulis ( close_writeacara) dan berjalan rsyncpada titik itu. Perhatikan bahwa rsync dimungkinkan untuk mengambil versi file yang tidak lengkap, jika Anda menyimpan dua kali berturut-turut dengan cepat, sebelum rsync menyelesaikan tugasnya dari penyimpanan pertama.

Vim, di sisi lain, menggunakan strategi write-then-move - sesuatu yang berpengaruh

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

Apa yang terjadi pada versi file yang lama adalah file itu dihapus pada titik di mana versi baru dipindahkan ke tempatnya. Pada titik ini, inotifywaitperintah kembali, karena file yang diperintahkan untuk ditonton tidak lagi ada. (Yang baru somefileadalah file yang berbeda dengan nama yang sama.) Jika Vim telah dikonfigurasi untuk membuat file cadangan, apa yang akan terjadi adalah sesuatu seperti

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

dan inotifywaitsekarang akan menonton cadangan.

Untuk informasi lebih lanjut tentang strategi penyimpanan file, lihat Bagaimana melakukan pembaruan langsung saat program sedang berjalan? dan Izin file dan penyimpanan

Vim dapat diperintahkan untuk menggunakan strategi timpa: matikan backupcopyopsi ( :set nobackupcopy). Ini berisiko, seperti ditunjukkan di atas.

Untuk menangani kedua strategi simpan, perhatikan direktori dan filter keduanya close_writeserta moved_toacara 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 'SANGAT berhenti menjadi jahat'
sumber
Kelemahan dari metode yang diusulkan di sini adalah ketika Anda menulis beberapa file "sekaligus", perintah Anda akan dijalankan sekali untuk setiap file. Saya mengedit kode, jadi saya dapat memodifikasi header dan beberapa unit terjemahan lainnya dan :wa. Kemudian build saya dijalankan sekali untuk setiap file yang ditulis.
Penebusan Terbatas
@LimitedAtonement Itu kasus penggunaan yang jauh lebih rumit daripada yang ada di pertanyaan ini. Untuk kasus penggunaan Anda, Anda harus menunggu sedikit setelah satu file disimpan. File tidak pernah benar-benar dimodifikasi "sekaligus". Jika Anda menyimpan banyak file dengan :wa, Anda mendapatkan acara inotify berturut-turut. Anda harus menunggu setelah yang pertama untuk melihat apakah orang lain akan datang. Tetapi Anda dapat menggunakan kode yang disajikan di sini: kompleksitas tambahan akan masuk ke dalam .
Gilles 'SANGAT berhenti jahat'
@Gilles saya memutuskan while true; do inotifywait ... [no -m]; make; sleep .1; done;atau lebih. Ada beberapa gotcha, tetapi saya telah tiba di sesuatu yang sangat bisa diterapkan.
Penebusan Terbatas