Tôi đang tìm một shell-liner để tìm tập tin cũ nhất trong cây thư mục.
Tôi đang tìm một shell-liner để tìm tập tin cũ nhất trong cây thư mục.
Câu trả lời:
Tác phẩm này (được cập nhật để kết hợp với đề xuất của Daniel Andersson):
find -type f -printf '%T+ %p\n' | sort | head -n 1
find
trống vì thực tế tôi có tên tệp chứa dòng mới.
Cái này dễ mang theo hơn một chút và vì nó không phụ thuộc vào find
phần mở rộng GNU -printf
, nên nó cũng hoạt động trên BSD / OS X:
find . -type f -print0 | xargs -0 ls -ltr | head -n 1
Nhược điểm duy nhất ở đây là nó hơi bị giới hạn về kích thước ARG_MAX
(điều này không liên quan đến hầu hết các hạt nhân mới hơn). Vì vậy, nếu có nhiều hơn các getconf ARG_MAX
ký tự được trả về (262.144 trên hệ thống của tôi), thì nó không mang lại cho bạn kết quả chính xác. Nó cũng không tuân thủ POSIX vì -print0
và xargs -0
không.
Một số giải pháp khác cho vấn đề này được nêu ra ở đây: Làm cách nào tôi có thể tìm thấy tệp mới nhất (mới nhất, sớm nhất, cũ nhất) trong một thư mục? - Wiki của Greg
xargs: ls: terminated by signal 13
lỗi như là một tác dụng phụ. Tôi đoán đó là SIGPIPE. Tôi không biết tại sao tôi không gặp phải lỗi tương tự khi tôi sắp xếp đầu ra của giải pháp.
head
lệnh thoát khi nó đã đọc một dòng và do đó "phá vỡ" đường ống, tôi nghĩ vậy. Bạn không nhận được lỗi vì sort
dường như không phàn nàn về điều đó, nhưng ls
trong trường hợp khác.
xargs
cần phải gọi ls
nhiều lần. Trong trường hợp đó, các kết quả đầu ra được sắp xếp của nhiều lệnh đó sẽ được kết hợp khi chúng được hợp nhất.
ls
nó và đánh dấu tập tin cũ nhất, giải pháp của bạn có thể sẽ vượt quá giới hạn độ dài dòng lệnh, gây ls
ra nhiều lần. Bạn sẽ nhận được câu trả lời sai nhưng bạn sẽ không bao giờ biết.
Các lệnh lệnh sau được đảm bảo hoạt động với bất kỳ loại tên tệp lạ nào:
find -type f -printf "%T+ %p\0" | sort -z | grep -zom 1 ".*" | cat
find -type f -printf "%T@ %T+ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //'
stat -c "%y %n" "$(find -type f -printf "%T@ %p\0" | \
sort -nz | grep -zom 1 ".*" | sed 's/[^ ]* //')"
Sử dụng byte byte ( \0
) thay cho ký tự linefeed ( \n
) đảm bảo đầu ra của find sẽ vẫn có thể hiểu được trong trường hợp một trong các tên tệp chứa ký tự linefeed.
Việc -z
chuyển đổi làm cho cả sort và grep chỉ diễn giải các byte rỗng thành các ký tự cuối dòng. Vì không có công tắc như vậy cho đầu, chúng tôi sử dụng grep -m 1
thay thế (chỉ một lần xuất hiện).
Các lệnh được sắp xếp theo thời gian thực hiện (được đo trên máy của tôi).
Lệnh đầu tiên sẽ chậm nhất vì nó phải chuyển đổi mọi thời gian của tệp thành định dạng có thể đọc được trước tiên và sau đó sắp xếp các chuỗi đó. Đường ống để mèo tránh tô màu đầu ra.
Lệnh thứ hai nhanh hơn một chút. Mặc dù nó vẫn thực hiện chuyển đổi ngày, nhưng việc sắp xếp bằng số ( sort -n
) các giây trôi qua vì thời gian Unix nhanh hơn một chút. sed xóa các giây kể từ Unix epoch.
Lệnh cuối cùng không có chuyển đổi nào cả và nên nhanh hơn đáng kể so với hai lệnh đầu tiên. Lệnh find sẽ không hiển thị mtime của tệp cũ nhất, vì vậy cần có stat.
Mặc dù câu trả lời được chấp nhận và những người khác ở đây thực hiện công việc, nhưng nếu bạn có một cây rất lớn, tất cả chúng sẽ sắp xếp toàn bộ các tệp.
Sẽ tốt hơn nếu chúng ta có thể liệt kê chúng và theo dõi những cái cũ nhất mà không cần phải sắp xếp gì cả.
Đó là lý do tại sao tôi đưa ra giải pháp thay thế này:
ls -lRU $PWD/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($1,0,1)=="/") { pat=substr($1,0,length($0)-1)"/"; }; if( $6 != "") {if ( $6 < oldd ) { oldd=$6; oldf=pat$8; }; print $6, pat$8; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Tôi hy vọng nó có thể giúp được gì, ngay cả khi câu hỏi hơi cũ.
Chỉnh sửa 1: thay đổi này cho phép phân tích tệp và thư mục có khoảng trắng. Nó đủ nhanh để phát hành nó trong thư mục gốc /
và tìm tập tin cũ nhất từ trước đến nay.
ls -lRU --time-style=long-iso "$PWD"/* | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { gsub(/-/,"",$6); if (substr($0,0,1)=="/") { pat=substr($0,0,length($0)-1)"/"; $6="" }; if( $6 ~ /^[0-9]+$/) {if ( $6 < oldd ) { oldd=$6; oldf=$8; for(i=9; i<=NF; i++) oldf=oldf $i; oldf=pat oldf; }; count++;}} END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
Lệnh khám phá:
Chạy nó:
~ $ thời gian ls -lRU "$ PWD" / * | v.v.
Ngày cũ nhất: 19691231
Tệp: /home/.../.../backupold/.../EXAMPLES/how-to-program.txt
Tổng số so sánh: 111438
số 0m1.135 thật
người dùng 0m0.872s
sys 0m0.760s
EDIT 2: Cùng khái niệm, giải pháp tốt hơn sử dụng find
để xem xét thời gian truy cập (sử dụng %T
với người đầu tiên printf
cho thời gian sửa đổi hoặc %C
cho thay đổi trạng thái thay).
find . -wholename "*" -type f -printf "%AY%Am%Ad %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
EDIT 3: Lệnh dưới đây sử dụng thời gian sửa đổi và cũng in tiến trình tăng dần khi nó tìm thấy các tệp cũ hơn và cũ hơn, rất hữu ích khi bạn có một số dấu thời gian không chính xác (như 1970-01-01):
find . -wholename "*" -type f -printf "%TY%Tm%Td %h/%f\n" | awk 'BEGIN {cont=0; oldd=strftime("%Y%m%d"); } { if ($1 < oldd) { oldd=$1; oldf=$2; for(i=3; i<=NF; i++) oldf=oldf " " $i; print oldd " " oldf; }; count++; } END { print "Oldest date: ", oldd, "\nFile:", oldf, "\nTotal compared: ", count}'
ls
là không tốt cho kịch bản vì đầu ra của nó không có nghĩa là cho máy móc, định dạng đầu ra khác nhau giữa các lần triển khai. Như bạn đã nói find
là tốt cho kịch bản nhưng cũng có thể tốt để thêm thông tin đó trước khi nói về ls
các giải pháp.
Vui lòng sử dụng ls - trang man cho bạn biết cách đặt hàng thư mục.
ls -clt | head -n 2
-N 2 là vì vậy bạn không nhận được "tổng" trong đầu ra. Nếu bạn chỉ muốn tên của tập tin.
ls -t | head -n 1
Và nếu bạn cần danh sách theo thứ tự bình thường (lấy tệp mới nhất)
ls -tr | head -n 1
Dễ dàng hơn nhiều so với việc sử dụng find, nhanh hơn và mạnh mẽ hơn - không phải lo lắng về các định dạng đặt tên tệp. Nó nên hoạt động trên hầu hết các hệ thống.
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1
sort -n
.
Dường như bởi "người già" nhất, hầu hết mọi người đều cho rằng bạn có nghĩa là "thời gian sửa đổi lâu đời nhất". Điều đó có lẽ đã được sửa, theo cách giải thích nghiêm ngặt nhất về "lâu đời nhất", nhưng trong trường hợp bạn muốn người có thời gian truy cập lâu nhất , tôi sẽ sửa đổi câu trả lời tốt nhất như vậy:
find -type f -printf '%A+ %p\n' | sort | head -n 1
Hãy chú ý %A+
.
set $(find /search/dirname -type f -printf '%T+ %h/%f\n' | sort | head -n 1) && echo $2
find ./search/dirname -type f -printf '%T+ %h/%f\n'
in ngày và tên tệp trong hai cột.sort | head -n1
giữ dòng tương ứng với tập tin cũ nhất.echo $2
hiển thị cột thứ hai, tức là tên tệp.
find -type f -printf '%T+ %p\n' | sort | head -1