SCP tắt tệp sửa đổi gần đây nhất trong một thư mục từ xa


1

Có một lệnh đơn giản để SCP tệp được sửa đổi gần đây nhất trong một thư mục trên một máy chủ từ xa không? Tôi có thể tìm ra cách để làm điều đó từ địa phương đến từ xa ... đại loại như: scp ``ls -Art | tail -n 1\`` usr@remote:/var/log/yeet Làm thế nào tôi có thể làm điều tương tự nhưng từ xa đến địa phương. (Vì vậy, hãy lấy tệp được sửa đổi gần đây nhất từ ​​yeet và sao chép nó vào máy chủ cục bộ)

Câu trả lời:


0

Có một vài vấn đề ở đây.

Phân tích cú pháp ls

Trước hết bạn không nên phân tích cú phápls . Của bạn ls -Art | tail -n 1là thiếu sót và nó không thể được sửa chữa đáng tin cậy. Một sự thay thế đáng tin cậy tiêu chuẩn là findvà / hoặc làm việc với các dòng kết thúc null.

Ngoài ra, tôi giả sử bạn cần tệp được sửa đổi gần đây nhất (không phải là thư mục) trực tiếp trong thư mục hiện tại (không phải trong thư mục con).

Khả năng phân tích các mục đầu vào dưới dạng danh sách kết thúc null thường không được POSIX yêu cầu. Nếu các công cụ của bạn đủ phong phú với các tùy chọn, thì đây là một sự thay thế mạnh mẽ cho ls -Art | tail -n 1:

find . -maxdepth 1 -type f -printf '%T@ %p\0' |
   sort -zrn |
   head -zn 1 |
   cut -z -d " " -f 2-

Nó mang lại kết quả là một tên tệp kết thúc null. Để làm một cái gì đó với nó, bạn cần đặt nó vào xargs -0 …, ví dụ:

… | xargs -0r cp -t "/target/dir/" --

hoặc (nếu bạn cpkhông hỗ trợ -t):

… | xargs -0r -I {} cp -- {} "/target/dir/"

Trong các lệnh này, có rất nhiều thứ không được POSIX yêu cầu (do đó không thể mang theo được), bao gồm cả --việc cpdừng phân tích cú pháp cho các tùy chọn, ví dụ: một tệp -Rsẽ không kích hoạt đệ quy thay vì được sao chép. Lưu ý rằng tên tệp rời khỏi find . …bắt đầu của chúng tôi .chắc chắn, vì vậy --có thể được bỏ qua một cách an toàn. Tôi đã sử dụng nó chỉ để chỉ ra một thực tiễn chung tốt khi giao dịch cp. Một thực hành tốt khác là trích dẫn các đường dẫn: nghĩa đen /target/dir/sẽ hoạt động mà không có dấu ngoặc kép, nhưng sau khi bạn thay thế ví dụ này bằng đường dẫn đích cụ thể của mình, bạn có thể cần dấu ngoặc kép, vì vậy dù sao tôi cũng đang sử dụng chúng.

Trong trường hợp (cục bộ đến từ xa) bạn sẽ sử dụng scpthay vì cp. Nó có thể có các quirks riêng trong khi phân tích các đối số.

Lệnh tuân thủ POSIX nhưng hoạt động kém có thể là:

find . ! -name . -prune -type f -exec sh -c '
   [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
   wc -c)" -eq 0 ]' sh {} \; -print

Nó điều chỉnh một cách tiếp cận từ câu trả lời khác này để thay thế (không phải POSIX) -maxdepth 1. Nó sinh sản shđể làm tổfind … -exec … đáng tin cậy hai mệnh đề . Các findđầu dò bên ngoài tất cả các tập tin và cung cấp từng cái một vào bên trong find. Bên trong findtìm thấy tất cả các tệp mới hơn tệp đã cho, in một ký tự ( a) cho mỗi tệp mới hơn. wc -cđếm những nhân vật này. Nếu không có, điều đó có nghĩa là tệp đã cho là sửa đổi gần đây nhất; chỉ sau đó bên ngoài findin nó.

Có một vài tình huống khi bên ngoài findcó thể in nhiều hơn một tệp:

  • có hai hoặc nhiều tệp có cùng thời gian "mới nhất";
  • các tập tin trong thư mục được sửa đổi trong khi lệnh đang chạy;
  • bên trong findkhông thể thống kê một số tập tin.

Vì lý do này vì -quithành động cuối cùng của bên ngoài findsẽ hữu ích (lưu ý rằng nó cũng hữu ích với bên trong find, nhưng vì một lý do khác). Thật không may, -quitkhông phải là POSIX.

Tôi đã sử dụng -print( -print0không phải POSIX), tên tệp không chuẩn không phải là vấn đề vì bạn không cần phải chuyển đầu ra sang lệnh khác. Chỉ cần sử dụng -execthỏa thuận với tất cả các tên tập tin có thể đúng; ví dụ thay vì -printbạn sử dụng:

-exec yet_another_command {} \;

Bây giờ bạn đã biết cách tìm tệp sửa đổi gần đây nhất trong một thư mục cục bộ mà không cần phân tích cú pháp ls.

Tìm tập tin trên một hệ thống từ xa

Dù bạn chọn cách tiếp cận nào (bao gồm cả thiếu sót ls … | tail …), bạn cần chạy lệnh trên hệ thống từ xa (hoặc không, tôi sẽ đến ngoại lệ này sau) để tìm tệp mong muốn trong thư mục từ xa.

Cách tiếp cận rõ ràng nhất là sshvào hệ thống từ xa. Trong ngữ cảnh mới, hệ thống từ xa là cục bộ và máy tính cục bộ của bạn là từ xa. (Ở đây tôi đang sử dụng lệnh tuân thủ POSIX ở trên làm ví dụ, nhưng bạn có thể sử dụng lệnh đầu tiên của chúng tôi find … | sort -z … | head -z … | cut -z … | xargs -0 …nếu chỉ có hệ thống từ xa hỗ trợ tất cả các tùy chọn bắt buộc).

ssh usr@remote
# now on the remote system
cd "/source/dir/" &&
find . ! -name . -prune -type f -exec sh -c '
   [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
   wc -c)" -eq 0 ]' sh {} \; -exec scp {} usr@local:"/target/dir/" \;

Lưu ý nếu bạn muốn tránh cdvà sử dụng find /source/dir …thì có nhiều .thứ cần phải thay thế /source/dir. Đó là cách dễ dàng hơn với cd.

Bạn cần hệ thống cục bộ của mình khả dụng qua SSH từ xa. Nếu có NAT trên đường, bạn có thể bỏ qua nó bằng một cổng chuyển tiếp từ xa, đại loại như thế này:

ssh -R 12322:127.0.0.1:22 usr@remote
# now on the remote system the same cd + find as above
# only the scp part is different 
… -exec scp -P 12322 {} usr@127.0.0.1:"/target/dir/" \;

Lưu ý rằng nó làm cho cổng từ xa 12322dẫn đến cục bộ của bạn sshdvà bất kỳ người dùng hệ thống từ xa nào cũng có thể cố gắng sử dụng sai. Một vấn đề khác: hệ thống từ xa có thể được cấu hình để không cho phép bạn chuyển tiếp một cổng ở vị trí đầu tiên.

Bạn có thể muốn một lệnh duy nhất để gọi trên hệ thống cục bộ. Trong trường hợp này, một trích dẫn thích hợp là bắt buộc và nó thậm chí còn cồng kềnh hơn:

ssh usr@remote '
   cd "/source/dir/" &&
   find . ! -name . -prune -type f -exec sh -c '"'"'
      [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
      wc -c)" -eq 0 ]'"'"' sh {} \; -exec scp {} usr@local:"/target/dir/" \;
   '

Tôi hy vọng rắc rối nếu điều khiển từ xa scpcần phải hỏi mật khẩu của bạn mặc dù. Vì lý do này hoặc nếu bạn không thể chạy / tiếp cận địa phương của mình sshd, bạn có thể cần một cách tiếp cận khác.

Lệnh cục bộ này sẽ in tên tệp mong muốn thu được từ hệ thống từ xa:

ssh usr@remote '
   cd "/source/dir/" &&
   find . ! -name . -prune -type f -exec sh -c '"'"'
      [ "$(find . ! -name . -prune -type f -newer "$1" -exec printf a \; |
      wc -c)" -eq 0 ]'"'"' sh {} \; -print
   '

Bạn có thể sử dụng nó với các công cụ địa phương như xargsscp. Lưu ý rằng phân tích cú pháp những gì -printmang lại chỉ tốt hơn một chút so với phân tích cú pháp ls. Sử dụng -print0(không phải POSIX, có thể không khả dụng) hoặc -exec printf "%s\0" {} \;(nên hoạt động) thay vì -printđể có được tên tệp mong muốn dưới dạng chuỗi kết thúc null. Bây giờ tùy thuộc vào bạn, bạn sẽ làm gì với nó ở phía địa phương. Điều này hữu ích nếu bạn cần có một lệnh từ xa tuân thủ POSIX nhưng các công cụ trong hệ thống cục bộ của bạn rất phong phú với các tùy chọn.

Ngoại lệ đáng chú ý: sshfs

sshfscho phép bạn gắn kết usr@remote:"/source/dir/"như một /local/path/. Xem câu trả lời này của tôi , tôi sẽ không lặp lại chính mình để bao gồm tất cả các chi tiết. Trong trường hợp của bạn, quy trình (cục bộ) với các công cụ phong phú (không giới hạn ở POSIX) giống như:

sshfs usr@remote:"/source/dir/" "/local/path/"
find "/local/path/" -maxdepth 1 -type f -printf '%T@ %p\0' |
   sort -zrn |
   head -zn 1 |
   cut -z -d " " -f 2- |
   xargs -0r cp -t "/target/dir/" --
fusermount -u "/local/path/"

Điều đó thật tuyệt. Tất cả mọi thứ bạn làm bạn làm với các công cụ địa phương . Nếu chỉ bạn có thể sử dụng sshfscác công cụ ở phía xa và các tùy chọn có sẵn của chúng không còn quan trọng nữa. Cũng không thành vấn đề nếu bạn có thể tiếp cận hệ thống địa phương của mình từ bên ngoài. Và phương pháp là như nhau: từ xa đến cục bộ hoặc cục bộ đến từ xa, không thành vấn đề.

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.