Bagaimana cara menjalankan skrip secara otomatis ketika isi direktori berubah di Linux?

17

Saya ingin menjalankan skrip secara otomatis setiap kali file baru disalin ke direktori tertentu. Dengan kata lain, apakah ada cara di Linux untuk "menonton" direktori untuk perubahan dan kemudian menjalankan sesuatu sebagai respons terhadap perubahan?

GeneQ
sumber
Diskusi ini telah diadakan di setiap situs stackexchange;) lihat superuser.com/questions/181517/... stackoverflow.com/questions/4380527/… dll.
masterxilo

Jawaban:

17

Jika Anda cukup beruntung berada di distribusi berbasis debian apt-get install dnotify,. Distribusi lain mungkin memiliki sesuatu yang mirip - cari dnotifynamanya.

dnotify adalah program sederhana berbasis Linux dnotify API kernel 2.4.19 +. dnotify dapat menjalankan perintah yang ditentukan setiap kali isi dari direktori tertentu berubah. Itu dijalankan dari baris perintah dan mengambil dua argumen: satu atau lebih direktori untuk dipantau dan perintah untuk dieksekusi setiap kali direktori telah berubah. Opsi mengontrol peristiwa apa yang akan memicu: kapan file dibaca di direktori, kapan satu file dibuat, dihapus, dan sebagainya.

Jika Anda ingin menangani ini di dalam program Anda sendiri, dnotify juga merupakan API yang ingin Anda gunakan.

MikeyB
sumber
4
@ MikeB, setelah Googling memberitahukan Anda, saya akhirnya menggunakan inotify, yang ternyata lebih dari itu. Terima kasih telah menunjukkan saya arah yang benar. apt-get install inotify-tools
GeneQ
7
@GeneQ, inotify telah menggantikan dnotify.
David
1
Demikian juga pada Gentoo:emerge inotify-tools
James Sneeringer
Ya, saya akan mengatakan, kernel 2.4.19 adalah semacam kuno ;-) inotify adalah cara untuk pergi.
David Z
Oh yeah ... aku lupa yang lebih baru :)
MikeyB
12

Anda dapat menjalankan skrip dengan inotify-tools, seperti ini. Ini akan menonton direktori untuk perubahan dalam file yang dimodifikasi, file baru, dan file yang dihapus, kemudian akan menjalankan skrip.

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done
pengguna7119
sumber
Hanya memperhitungkan bahwa jika direktori sumber berubah saat sedang disalin, inotifywait TIDAK akan melihatnya dan perubahan itu tidak akan disalin sampai perubahan lebih lanjut setelah salinan selesai. Mungkin bukan masalah.
Raúl Salinas-Monteagudo
Bagaimana Anda bisa menjalankan ini dalam mode daemon?
Chris F
4

incron pada dasarnya adalah apa yang Anda inginkan, saya pikir. Ini menggunakan inotify sebagai mekanisme notifikasi (yang, seperti yang orang lain tunjukkan, menggantikan notnotify), tetapi tidak memerlukan skrip yang terus berjalan, menggunakan inotifywait atau yang serupa (walaupun, jelas, daemon incron berjalan sepanjang waktu). 'Crontab' di seluruh sistem dan 'crontab' pengguna didukung dengan cara yang mirip dengan cron standar, tetapi alih-alih menentukan waktu sebagai pemicu, inotifikasi acara dan nama file / direktori yang digunakan.

incron dikemas untuk banyak distribusi, termasuk Ubuntu dan Debian, saya percaya.

Andrew Ferrier
sumber
0

Ada perangkat lunak hanya untuk tujuan ini, autoenv Anda mungkin ingin memeriksanya.

DukeLion
sumber
0

entr adalah alat pemberitahuan file paling sederhana dan paling komposable yang pernah saya lihat. Penggunaannya dioptimalkan untuk menonton file daripada direktori, tetapi juga dapat menyelesaikan kasus Anda.

Untuk mendeteksi dan bertindak pada file yang ditambahkan, gabungkan dengan alat lain seperti mis make. entrtidak mengirim nama atau semacamnya, itu hanya menjalankan apa yang Anda perintahkan untuk dijalankan.

Untuk memeriksa file yang ditambahkan dalam direktori:

## entr exits with rc=0 when terminated
## rc=1 when watched files go away or don't exist to begin with
## rc=2 when new files arrive in watched directories
until echo /path/to/directory_to_watch | entr -d do_stuff
do sleep 1; done

Jika Anda juga ingin bertindak ketika file yang ada berubah:

## Here's why it comes in handy that entr exits when new files are added --
## find gets re-run.
until find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/* |
    entr -d do_stuff
do sleep 1; done

... dan di situlah mekanisme loop berguna, karena findekspresi akan berjalan lagi jika file ditambahkan.

Jika Anda ingin penanganan kesalahan yang lebih baik dan ingin memastikan hal-hal hanya berjalan sekali per file yang ditambahkan / dihapus, hal-hal menjadi sedikit aneh, tetapi untuk kasus-kasus sederhana ini brilian.


EDIT: Jika Anda ingin melakukan ini pada tingkat sistem, sesuatu seperti incron , cukup tambahkan skrip ke manajer proses favorit Anda (seperti s6 , runit , systemd atau sysvinit dan lewati loop:

#!/bin/bash
exec entr -d do_stuff < <(find /path/to/directory_to_watch/ -path /path/to/directory_to_watch/*)

The execdan substitusi proses ( <(...)) adalah penting ketika menjalankan dari manajer proses, untuk menangani sinyal dengan benar (yaitu untuk mendapatkan shell keluar dari jalan).

klak
sumber