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 1
là 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à find
và / 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 cp
khô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 cp
dừng phân tích cú pháp cho các tùy chọn, ví dụ: một tệp -R
sẽ 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 scp
thay 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 find
tì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 find
in nó.
Có một vài tình huống khi bên ngoài find
có 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
find
không thể thống kê một số tập tin.
Vì lý do này vì -quit
hành động cuối cùng của bên ngoài find
sẽ 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, -quit
không phải là POSIX.
Tôi đã sử dụng -print
( -print0
khô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 -exec
thỏa thuận với tất cả các tên tập tin có thể đúng; ví dụ thay vì -print
bạ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à ssh
và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 cd
và 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 12322
dẫn đến cục bộ của bạn sshd
và 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 scp
cầ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ư xargs
và scp
. Lưu ý rằng phân tích cú pháp những gì -print
mang 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
sshfs
cho 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 sshfs
cá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 đề.