Xác định xem tập tin đang trong quá trình được viết?


25

Tôi cần triển khai một quy trình tự động (thông qua tập lệnh cron 1 phút) để tìm các tệp tar trong một thư mục cụ thể. Nếu một tập tin tar được tìm thấy, nó được xác định vị trí thích hợp và sau đó tập tin tar bị xóa.

Các tập tin tar được tự động sao chép vào máy chủ này qua SSH từ một máy chủ khác. Trong một số trường hợp, các tệp tar cực kỳ lớn, với rất nhiều tệp.

Vấn đề mà tôi đang mong đợi gặp phải: Nếu phải mất> 1 phút để tệp tar được sao chép vào máy chủ và tập lệnh cron chạy một lần mỗi phút, nó sẽ thấy tệp .tar.gz và cố gắng thực hiện gỡ bỏ nó, mặc dù tập tin tar vẫn đang trong quá trình ghi.

Có cách nào (thông qua các lệnh bash) để kiểm tra xem một tệp hiện đang được ghi vào hay không, nếu đó chỉ là một phần của tệp, v.v.?

Một cách khác tôi đã nghĩ đến là để tệp được sao chép dưới dạng một phần mở rộng tệp khác (như .tar.gz.part) và sau đó được đổi tên thành .tar.gzsau khi quá trình chuyển hoàn tất. Nhưng tôi đã tìm ra rằng tôi sẽ cố gắng tìm hiểu xem có cách nào đơn giản để xác định xem tập tin có phải là toàn bộ dòng lệnh hay không ... Có manh mối nào không?


2
Làm thế nào chính xác là tập tin được chuyển? Ví dụ: rsyncsử dụng tên tệp tạm thời trong quá trình chuyển (theo mặc định) và chỉ sau khi tệp được chuyển hoàn toàn, đổi tên thành tên tệp thực tế.
Piskvor

Câu trả lời:


12

Bạn đang đi đúng hướng, đổi tên tệp là một hoạt động nguyên tử, vì vậy thực hiện đổi tên sau khi tải lên là đơn giản, thanh lịch và không dễ bị lỗi. Một cách tiếp cận khác tôi có thể nghĩ đến là sử dụng lsof | grep filename.tar.gzđể kiểm tra xem tệp có đang được truy cập bởi một quy trình khác không.


7
( lsof filename.tar.gzhiệu quả hơn và chính xác hơn lsof | grep filename.tar.gz)
Rich

BTW, nó phải là một đường dẫn tuyệt đối của tên tệp
DennisLi

14

Đặt cược tốt nhất của bạn là sử dụng lsofđể xác định xem một tập tin đã được mở bởi bất kỳ quá trình:

#  lsof -f -- /var/log/syslog
COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF  NODE NAME
rsyslogd 1520 syslog    1w   REG  252,2    72692 16719 /var/log/syslog

Bạn không thể dễ dàng biết nếu nó đang trong quá trình viết, nhưng nếu nó được viết cho, nó PHẢI được mở.


Chỉnh sửa: hãy giải quyết vấn đề thực tế ở đây thay vì cố gắng thực hiện giải pháp đề xuất!

Sử dụng rsync để chuyển tệp:

  rsync -e ssh remote:big.tar.gz .

Bằng cách này, tệp sẽ không được sao chép trên đầu trang hiện có nhưng được sao chép vào tệp tạm thời ( .big.tar.gz.XXXXXX) cho đến khi quá trình chuyển hoàn tất, sau đó được chuyển vào vị trí.


6

Một chút cũ, nhưng hầu hết các câu trả lời hoàn toàn bỏ lỡ điểm của câu hỏi:

Nhưng tôi đã tìm ra rằng tôi sẽ cố gắng tìm hiểu xem có cách nào đơn giản để xác định xem tập tin có hoàn toàn ở dòng lệnh không ...

Nói chung, không có. Bạn chỉ đơn giản là không có đủ thông tin để xác định điều đó.

Bởi vì xác định rằng tệp được đóng không giống như xác định nếu tệp là toàn bộ . Ví dụ: một tệp sẽ bị "đóng" nếu kết nối bị mất giữa chừng trong quá trình chuyển.

Chỉ có câu trả lời của @ Alex mới đúng. Và thậm chí anh ta đã rơi vì sử dụng lsofphần nào.

Để xác định xem tệp đã được đầy đủ chưa, chuyển thành công cần nhiều dữ liệu hơn. Nhu la:

Một cách khác tôi đã nghĩ đến là để tệp được sao chép dưới dạng một phần mở rộng tệp khác (như .tar.gz.part) và sau đó được đổi tên thành .tar.gzsau khi quá trình chuyển hoàn tất.

Đó là một cách hoàn toàn tốt để thông báo rằng tập tin đã được chuyển đầy đủ và thành công. Bạn cũng có thể di chuyển các tệp từ thư mục này sang thư mục khác miễn là bạn ở trong cùng một hệ thống tệp. Hoặc có người gửi gửi một filename.donetập tin trống để hoàn thành tín hiệu.

Nhưng tất cả các phương pháp phải dựa vào người gửi bằng cách nào đó báo hiệu rằng việc chuyển tiền đã hoàn tất thành công. Bởi vì chỉ có người gửi có thông tin đó.

Một số định dạng tệp (như tệp PDF) có dữ liệu trong đó cho phép bạn xác định xem tệp đã hoàn tất chưa. Nhưng bạn phải mở và đọc khá nhiều toàn bộ tập tin để tìm hiểu.

lsofsẽ chỉ cho bạn biết tệp không còn mở nữa - nó sẽ không cho bạn biết lý do tại sao nó không còn mở nữa. Nó cũng sẽ không cho bạn biết các tập tin được cho là lớn như thế nào.


1
Tôi không thể nâng cao điều này đủ. Làm tốt công việc giải quyết vấn đề XY ở đây.
Beefster

5

Cách tốt nhất để làm điều này là sử dụng incron ("inotify cron system"). Nó cho phép bạn đặt một đồng hồ inotify trên một thư mục mà sau đó sẽ thông báo cho bạn về các hoạt động tập tin. Trong trường hợp này, bạn nên xem thư mục để xem close_write. Điều đó sẽ cho phép bạn chạy lệnh sau khi tệp được đóng sau khi ghi.


2

Có vẻ như lsof có thể phát hiện chế độ nào mà tệp được mở trong:

lsof -f -- a_file
COMMAND   PID  USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     52391 bob    1w   REG    1,2       15 19545007 a_file

Xem nó nói 1w ở đâu? Điều đó có nghĩa là số mô tả tệp là 1 và chế độ là w hoặc ghi.


Các FDchương trình lĩnh vực 3rcho tôi khi tập tin được mở ra để đọc.
Sopalajo de Arrierez

0

Việc sử dụng inotifywaitcó thể đạt được những gì bạn đang theo đuổi - nó có khả năng đợi cho đến khi việc ghi tệp kết thúc trước khi thực hiện lệnh.

Sau đây sẽ liên tục xem một thư mục cho các tệp mới và thực hiện lệnh trong vòng lặp khi việc ghi vào tệp đã kết thúc.

WATCH_DIR=/directory/to/monitor
DEST_DIR=/x/y/z

/usr/bin/inotifywait --recursive --monitor --quiet -e moved_to -e close_write --format '%w%f' "$WATCH_DIR" | while read -r INPUT_FILE; do

mv "$0" "$DEST_DIR"

done

Để biết thêm tùy chọn cấu hình, hãy xem https://linux.die.net/man/1/inotifywatch

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.