Làm cách nào để tìm tập tin cũ nhất trong cây thư mục


Câu trả lời:


72

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

8
Ít gõ hơn:find -type f -printf '%T+ %p\n' | sort | head -1
Daniel Andersson

1
Tôi nhận được không gian trống vì dòng đầu tiên của tôi từ đây findtrống vì thực tế tôi có tên tệp chứa dòng mới.
林果

1
Tôi có thể hỏi nếu điều này sử dụng ngày tạo hoặc sửa đổi?
MrMesees

1
Linux không lưu trữ ngày tạo tệp ở bất cứ đâu [*]. Điều này sử dụng ngày sửa đổi. [*] Điều này thực sự là không đúng sự thật; ext4 lưu trữ ngày tạo inode, nhưng nó không được hiển thị thông qua bất kỳ cuộc gọi hệ thống nào và bạn cần sử dụng debugfs để xem nó.)
Marius Gedminas

11

Cái này dễ mang theo hơn một chút và vì nó không phụ thuộc vào findphầ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_MAXký 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ì -print0xargs -0khô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


Điều này cũng hoạt động, nhưng nó cũng phát ra một xargs: ls: terminated by signal 13lỗ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.
Marius Gedminas

Phiên bản của bạn cũng dễ dàng hơn để nhập từ bộ nhớ. :-)
Marius Gedminas

Vâng, đó là một đường ống bị hỏng. Tôi không nhận được điều này với cả hai phiên bản GNU và BSD của tất cả các lệnh đó, nhưng đó là headlệ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ì sortdường như không phàn nàn về điều đó, nhưng lstrong trường hợp khác.
slhck

4
Điều này phá vỡ nếu có rất nhiều tên tập tin xargscần phải gọi lsnhiề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.
Nicole Hamilton

2
Tôi nghĩ điều này còn tệ hơn việc đăng một kịch bản giả định tên tập tin không bao giờ chứa dấu cách. Rất nhiều thời gian, những thứ đó sẽ hoạt động vì tên tệp không có khoảng trắng. Và khi họ thất bại, bạn gặp lỗi. Nhưng điều này không có khả năng làm việc trong các trường hợp thực tế và thất bại sẽ không được khám phá. Trên bất kỳ cây thư mục nào đủ lớn để bạn không thể chỉ lsnó 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 lsra 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.
Nicole Hamilton

11

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 -zchuyể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 1thay 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.

Các trang man liên quan: find - grep - sed - sort - stat


5

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á:

  • ls -lRU --time-style = long-iso "$ PWD" / * liệt kê tất cả các tệp (*), định dạng dài (l), đệ quy (R), mà không sắp xếp (U) nhanh và chuyển nó thành awk
  • Awk sau đó BEGIN bằng cách đếm số 0 (tùy chọn cho câu hỏi này) và đặt ngày tháng cũ nhất là ngày hôm nay, định dạng YearMonthDay.
  • Vòng lặp chính đầu tiên
    • Lấy trường thứ 6, ngày, định dạng Năm-Tháng-Ngày và đổi nó thành YearMonthDay (nếu ls của bạn không xuất ra theo cách này, bạn có thể cần phải tinh chỉnh nó).
    • Sử dụng đệ quy, sẽ có các dòng tiêu đề cho tất cả các thư mục, ở dạng / thư mục / ở đây :. Lấy dòng này vào biến pat. (thay thế ":" cuối cùng thành "/"). Và đặt $ 6 thành không có gì để tránh sử dụng dòng tiêu đề làm dòng tệp hợp lệ.
    • nếu trường $ 6 có số hợp lệ, đó là ngày. So sánh nó với oldd ngày cũ.
    • Nó có già không Sau đó lưu các giá trị mới cho oldd ngày cũ và tên tệp cũ oldf. BTW, oldf không chỉ là lĩnh vực thứ 8, mà từ thứ 8 đến cuối. Đó là lý do tại sao một vòng lặp để nối từ 8 đến cuối (kết thúc).
    • Đếm tiến bộ của một
    • KẾT THÚC bằng cách in kết quả

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 %Tvới người đầu tiên printfcho thời gian sửa đổi hoặc %Ccho 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}'

Nó vẫn cần tweeking để chấp nhận các tập tin với không gian. Tôi sẽ làm điều đó sớm thôi.
Bác sĩ Beco

Tôi nghĩ rằng phân tích ls cho các tệp có khoảng trắng không phải là một ý tưởng tốt. Có thể sử dụng find.
Bác sĩ Beco

Chỉ cần chạy nó trong toàn bộ cây "/". Thời gian sử dụng: Tổng số so sánh: 585744 thực 2m14.017s người dùng 0m8.181s sys 0m8.473s
Tiến sĩ Beco

Việc sử dụng lslà 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 findlà 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ề lscác giải pháp.
Sampo Sarrala

4

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.


6
Điều này chỉ hoạt động nếu các tệp nằm trong một thư mục, trong khi câu hỏi của tôi là về cây thư mục.
Marius Gedminas

2
find ! -type d -printf "%T@ %p\n" | sort -n | head -n1

Điều này sẽ không hoạt động đúng nếu có các tệp cũ hơn ngày 9 tháng 9 năm 2001 (1000000000 giây kể từ Unix epoch). Để kích hoạt sắp xếp số, sử dụng sort -n.
Dennis

Điều này giúp tìm cho tôi tệp, nhưng thật khó để xem nó bao nhiêu tuổi mà không chạy lệnh thứ hai :)
Marius Gedminas

0

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+.


-1
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.

1
Chào mừng bạn đến với Siêu người dùng! Trong khi điều này có thể trả lời câu hỏi, nó sẽ là một câu trả lời tốt hơn nếu bạn có thể cung cấp một số lời giải thích tại sao nó làm như vậy.
DavidPostill

1
Lưu ý, một số người cũng yêu cầu một số giải thích về câu trả lời đã xóa (giống hệt) trước đó của bạn.
DavidPostill

Điều gì khó trả lời? tìm ./search/dirname -type f -printf '% T +% h /% f \ n' | sắp xếp | head -n 1 Nó hiển thị hai cột là thời gian và đường dẫn của tệp. Nó là cần thiết để loại bỏ cột đầu tiên. Sử dụng set và echo $ 2
Dima

1
Bạn nên cung cấp giải thích thay vì chỉ dán một dòng lệnh, theo yêu cầu của một số người dùng khác.
Ob1lan

1
Làm thế nào là khác nhau sau đó câu trả lời được chấp nhận?
Ramhound
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.