Làm cách nào để tự động chạy tập lệnh khi nội dung của thư mục thay đổi trong Linux?


17

Tôi muốn tự động chạy tập lệnh bất cứ khi nào tập tin mới được sao chép vào một thư mục cụ thể. Nói cách khác, Linux có cách nào để "xem" một thư mục để thay đổi và sau đó chạy một cái gì đó để đáp ứng với sự thay đổi không?


Cuộc thảo luận này đã được tổ chức trên mọi trang web stackexchange;) xem superuser.com/questions/181517/
Thẻ

Câu trả lời:


17

Nếu bạn đủ may mắn để được phân phối dựa trên debian , apt-get install dnotify. Các bản phân phối khác có thể có một cái gì đó tương tự - tìm dnotifytên.

dnotify là một chương trình đơn giản dựa trên API dnotify của Linux kernel 2.4.19 +. dnotify có thể thực thi một lệnh được chỉ định mỗi khi nội dung của một thư mục cụ thể thay đổi. Nó được chạy từ dòng lệnh và nhận hai đối số: một hoặc nhiều thư mục để giám sát và một lệnh để thực thi bất cứ khi nào một thư mục đã thay đổi. Tùy chọn kiểm soát những sự kiện sẽ kích hoạt: khi một tệp được đọc trong thư mục, khi một tệp được tạo, xóa và vv.

Nếu bạn muốn xử lý việc này trong chương trình của riêng bạn, thì dnotify cũng là API bạn muốn sử dụng.


4
@MikeB, sau khi Googling từ chối bạn đề xuất, cuối cùng tôi đã sử dụng inotify, điều này dường như vượt quá nó. Cảm ơn đã chỉ cho tôi hướng đi đúng. apt-get install inotify-tools
GeneQ

7
@GeneQ, inotify đã thay thế dnotify.
David

1
Tương tự như vậy trên Gentoo:emerge inotify-tools
James Sneeringer

Vâng, tôi sẽ nói, kernel 2.4.19 là một loại cổ xưa ;-) inotify là con đường để đi.
David Z

Ồ vâng ... Tôi quên mất cái gần đây hơn :)
MikeyB

12

Bạn có thể chạy một tập lệnh với các công cụ inotify, đại loại như thế này. Nó sẽ xem thư mục để thay đổi các tệp đã sửa đổi, tệp mới và tệp bị xóa, sau đó nó sẽ thực thi tập lệnh.

#!/bin/sh
while inotifywait -e modify -e create -e delete /home/me/code; do
    rsync [options] /home/me/code/ /media/nfs/code/ 
done

Chỉ cần lưu ý rằng nếu thư mục nguồn thay đổi trong khi nó đang được sao chép, inotifywait sẽ KHÔNG thấy nó và những thay đổi đó sẽ không được sao chép cho đến khi thay đổi thêm sau khi bản sao kết thúc. Có lẽ không phải là một vấn đề mặc dù.
Raúl Salinas-Monteagudo

Làm thế nào bạn có thể chạy này trong chế độ daemon?
Chris F

4

incron về cơ bản là những gì bạn muốn, tôi nghĩ. Nó sử dụng inotify làm cơ chế thông báo (như những gì người khác đã chỉ ra, thay thế cho dnotify), nhưng không yêu cầu một tập lệnh liên tục chạy, sử dụng inotifywait hoặc tương tự (mặc dù, rõ ràng, trình nền incron đang chạy mọi lúc). 'Crontabs' trên toàn hệ thống và 'crontabs' trên toàn hệ thống được hỗ trợ theo cách tương tự như cron tiêu chuẩn, nhưng thay vì chỉ định thời gian làm trình kích hoạt, inotify sự kiện và tên tệp / thư mục được sử dụng.

incron được đóng gói cho nhiều bản phân phối, bao gồm Ubuntu và Debian, tôi tin thế.



0

entr là công cụ thông báo tập tin đơn giản và dễ kết hợp nhất mà tôi đã thấy. Việc sử dụng nó được tối ưu hóa để xem các tập tin hơn là các thư mục, nhưng nó cũng có thể giải quyết trường hợp của bạn.

Để phát hiện và hành động trên tệp đã thêm, hãy kết hợp nó với các công cụ khác như vd make. entrkhông gửi tên hoặc bất cứ thứ gì tương tự, nó chỉ đơn giản là chạy những gì bạn bảo nó chạy.

Để kiểm tra các tập tin được thêm vào trong một thư mục:

## 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

Nếu bạn cũng muốn hành động khi một tệp hiện có thay đổi:

## 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

... và đó là nơi cơ chế vòng lặp có ích, vì findbiểu thức sẽ chạy lại nếu một tệp được thêm vào.

Nếu bạn muốn xử lý lỗi tốt hơn và muốn đảm bảo mọi thứ chỉ chạy một lần cho mỗi tệp được thêm / xóa, mọi thứ sẽ hơi kỳ quặc, nhưng đối với những trường hợp đơn giản này thì thật tuyệt vời.


EDIT: Nếu bạn muốn làm điều này ở cấp độ hệ thống, đại loại như incron , chỉ cần thêm tập lệnh vào trình quản lý quy trình yêu thích của bạn (như s6 , runit , systemd hoặc sysvinit và bỏ qua vòng lặp:

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

Sự execthay thế và quá trình ( <(...)) rất quan trọng khi chạy từ trình quản lý quy trình, để xử lý tín hiệu đúng cách (nghĩa là lấy vỏ ra khỏi đường đi).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.