Làm thế nào để tìm đệ quy tệp sửa đổi mới nhất trong một thư mục?


242

Có vẻ như lskhông sắp xếp các tệp chính xác khi thực hiện cuộc gọi đệ quy:

ls -altR . | head -n 3

Làm cách nào tôi có thể tìm thấy tệp được sửa đổi gần đây nhất trong một thư mục (bao gồm cả thư mục con)?


Câu trả lời:


357
find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "

Đối với một cái cây khổng lồ, thật khó sortđể giữ mọi thứ trong bộ nhớ.

%T@cung cấp cho bạn thời gian sửa đổi như dấu thời gian unix, sort -nsắp xếp bằng số, tail -1lấy dòng cuối cùng (dấu thời gian cao nhất), cut -f2 -d" "cắt bỏ trường đầu tiên (dấu thời gian) khỏi đầu ra.

Chỉnh sửa: Cũng giống như -printfchỉ có GNU, việc sử dụng ajreals stat -ccũng vậy. Mặc dù có thể làm tương tự trên BSD, các tùy chọn định dạng là khác nhau ( -f "%m %N"có vẻ như)

Và tôi đã bỏ lỡ một phần của số nhiều; nếu bạn muốn sau đó thêm các tập tin mới nhất, chỉ bump lên tranh cãi đuôi.


7
Nếu vấn đề đặt hàng, bạn có thể chuyển đổi sử dụng sort -rn | head -3thay vì sort -n | tail -3. Một phiên bản cung cấp các tệp từ cũ nhất đến mới nhất, trong khi phiên bản còn lại chuyển từ mới nhất sang cũ nhất.
Don Faulkner

3
Tôi đã có một thư mục khổng lồ (khoảng mười nghìn tệp nhỏ) và tôi đã lo lắng về hiệu suất, nhưng ... lệnh này chạy trong chưa đầy một giây! Tuyệt vời, cảm ơn rất nhiều!!! :-)
lucaferrario 7/12/13

2
"Đối với một cái cây khổng lồ, thật khó để sắp xếp mọi thứ trong bộ nhớ." sortsẽ tạo các tệp tạm thời (trong /tmp) khi cần, vì vậy tôi không nghĩ đó là vấn đề đáng lo ngại.
Vladimir Panteleev

1
sửa đổi nó thành: -printf '%T@ %Tb %Td %TY %p\n'sẽ cung cấp cho bạn một dấu ngày (nếu cần) (tương tự ls)
bshea

1
Tôi tìm thấy đoạn văn sau ngắn hơn và có đầu ra dễ hiểu hơn:find . -type f -printf '%TF %TT %p\n' | sort | tail -1
snth

129

Theo dõi câu trả lời của @ plundra , đây là phiên bản BSD và OS X:

find . -type f -print0 | xargs -0 stat -f "%m %N" |
sort -rn | head -1 | cut -f2- -d" "

1
BSD / OS X có findhỗ trợ +thay thế \;không? Bởi vì điều đó làm điều tương tự (truyền nhiều tệp dưới dạng tham số), không có -print0 | xargs -0đường ống.
DevSolar

Phải làm gì nếu tôi muốn nhận được 5 hoặc n số tệp cuối cùng được sửa đổi theo thứ tự giảm dần?
khun Sơn

@khun Sơn đổi head -1thànhhead -5
Emerson Farrugia

20

Thay vì sắp xếp kết quả và chỉ giữ lại những kết quả được sửa đổi cuối cùng, bạn có thể sử dụng awk để chỉ in kết quả có thời gian sửa đổi lớn nhất (trong thời gian unix):

find . -type f -printf "%T@\0%p\0" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\0'

Đây sẽ là một cách nhanh hơn để giải quyết vấn đề của bạn nếu số lượng tệp đủ lớn.

Tôi đã sử dụng ký tự NUL (tức là '\ 0') vì về mặt lý thuyết, tên tệp có thể chứa bất kỳ ký tự nào (bao gồm cả khoảng trắng và dòng mới) nhưng điều đó.

Nếu bạn không có tên tệp bệnh lý như vậy trong hệ thống của mình, bạn cũng có thể sử dụng ký tự dòng mới:

find . -type f -printf "%T@\n%p\n" | awk '
    {
        if ($0>max) {
            max=$0; 
            getline mostrecent
        } else 
            getline
    } 
    END{print mostrecent}' RS='\n'

Ngoài ra, điều này hoạt động trong mawk quá.


Điều này có thể dễ dàng thích nghi để giữ ba gần đây nhất.
Tạm dừng cho đến khi có thông báo mới.

1
Điều này không hoạt động với mawk, thay thế tiêu chuẩn Debian.
ngày

Không, nhưng trong trường hợp đó bạn có thể sử dụng ký tự dòng mới nếu nó không làm phiền bạn;)
marco

10

Tôi gặp khó khăn khi tìm tệp sửa đổi cuối cùng trong Solaris 10. Không findprintftùy chọn và statkhông có sẵn. Tôi phát hiện ra giải pháp sau đây phù hợp với tôi:

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7 }' | sort | tail -1

Để hiển thị tên tệp cũng sử dụng

find . -type f | sed 's/.*/"&"/' | xargs ls -E | awk '{ print $6," ",$7," ",$9 }' | sort | tail -1

Giải trình

  • find . -type f tìm và liệt kê tất cả các tập tin
  • sed 's/.*/"&"/' kết thúc tên đường dẫn trong dấu ngoặc kép để xử lý khoảng trắng
  • xargs ls -Egửi đường dẫn được trích dẫn tới ls, -Etùy chọn đảm bảo rằng dấu thời gian đầy đủ (định dạng năm-tháng-ngày-phút-giây-giây-nano giây ) được trả về
  • awk '{ print $6," ",$7 }' chỉ trích ngày giờ
  • awk '{ print $6," ",$7," ",$9 }' trích xuất ngày, thời gian và tên tệp
  • sort trả về các tập tin được sắp xếp theo ngày
  • tail -1 chỉ trả về tệp sửa đổi cuối cùng

9

Điều này dường như hoạt động tốt, ngay cả với các thư mục con:

find . -type f | xargs ls -ltr | tail -n 1

Trong trường hợp có quá nhiều tập tin, hãy tinh chỉnh tìm kiếm.


1
Các -ltùy chọn lscó vẻ không cần thiết. Chỉ cần -trcó vẻ đủ.
Acumenus

6
Điều này dường như sắp xếp theo từng thư mục, vì vậy nó sẽ không nhất thiết phải hiển thị tệp mới nhất
Fabian Schmengler

1
Trong trường hợp có không gian trong đường dẫn tệp tốt hơn, hãy thực hiện:find . -type f -print0 | xargs -0 ls -ltr | tail -n 1
Bảo trì định kỳ

Điều này không tìm thấy các tập tin mới nhất cho tôi.
K.-Michael Aye

1
Hãy nghĩ rằng điều này sẽ phá vỡ nếu có không gian trong tên tệp
waferthin

7

Hiển thị tệp mới nhất với dấu thời gian có thể đọc được của con người:

find . -type f -printf '%TY-%Tm-%Td %TH:%TM: %Tz %p\n'| sort -n | tail -n1

Kết quả trông như thế này:

2015-10-06 11:30: +0200 ./foo/bar.txt

Để hiển thị nhiều tệp hơn, thay thế -n1bằng một số cao hơn


5

Tôi sử dụng một cái gì đó tương tự mọi lúc, cũng như danh sách top-k của các tệp được sửa đổi gần đây nhất. Đối với cây thư mục lớn, có thể nhanh hơn nhiều để tránh sắp xếp . Trong trường hợp chỉ là tệp 1 được sửa đổi gần đây nhất:

find . -type f -printf '%T@ %p\n' | perl -ne '@a=split(/\s+/, $_, 2); ($t,$f)=@a if $a[0]>$t; print $f if eof()'

Trên thư mục chứa 1,7 triệu tệp, tôi nhận được tệp gần đây nhất trong 3,4 giây, tăng tốc 7,5 lần so với giải pháp 25,5 giây bằng cách sử dụng sắp xếp.


Rất tuyệt: Tôi vừa trao đổi bản in cuối cùng với: system ("ls -l $ f") nếu eof () để xem ngày theo cách tốt, quá.
Martin T.

@MartinT. : tuyệt vời, và bạn được chào đón. Điều kỳ lạ đối với tôi là mọi người có bản năng sắp xếp mọi thứ (O (n log n)) khi phương thức O (n) có sẵn. Đây dường như là câu trả lời duy nhất tránh sắp xếp. BTW, mục tiêu của lệnh tôi đề xuất chỉ là tìm đường dẫn của tệp mới nhất. Bạn có thể đặt bí danh cho lệnh trong shell của mình (ví dụ như lastfile) và sau đó bạn có thể làm bất cứ điều gì bạn muốn với kết quả, chẳng hạn như ls -l $(lastfile .), hoặc open $(lastfile .)trên máy Mac), v.v.
Pierre D

Ồ, tôi đứng chính xác: Tôi thấy một câu trả lời khác bên dưới (@marco). +1.
Pierre D

4

Điều này đưa ra một danh sách được sắp xếp:

find . -type f -ls 2>/dev/null | sort -M -k8,10 | head -n5

Đảo ngược thứ tự bằng cách đặt '-r' trong lệnh sort. Nếu bạn chỉ muốn tên tệp, hãy chèn "awk '{print $ 11}' |" trước '| cái đầu'


3

Trên Ubuntu 13, những điều sau đây, có thể nhanh hơn một chút, vì nó đảo ngược sắp xếp và sử dụng 'đầu' thay vì 'đuôi', làm giảm công việc. Để hiển thị 11 tệp mới nhất trong cây:

tìm thấy . -type f -printf '% T @% p \ n' | sắp xếp -n -r | đầu -11 | cắt -f2- -d "" | sed -e 's, ^. / ,,' | xargs ls -U -l

Điều này cung cấp một danh sách ls hoàn chỉnh mà không cần sắp xếp lại và bỏ qua './' mà 'find' gây phiền nhiễu cho mỗi tên tệp.

Hoặc, như một hàm bash:

treecent () {
  local numl
  if [[ 0 -eq $# ]] ; then
    numl=11   # Or whatever default you want.
  else
    numl=$1
  fi
  find . -type f -printf '%T@ %p\n' | sort -n -r | head -${numl} |  cut -f2- -d" " | sed -e 's,^\./,,' | xargs ls -U -l
}

Tuy nhiên, hầu hết các công việc được thực hiện bằng giải pháp ban đầu của Plundra. Cảm ơn plundra.


3

Tôi phải đối mặt với cùng một vấn đề. Tôi cần tìm tập tin gần đây nhất theo cách đệ quy. tìm mất khoảng 50 phút để tìm.

Đây là một kịch bản nhỏ để làm điều đó nhanh hơn:

#!/bin/sh

CURRENT_DIR='.'

zob () {
    FILE=$(ls -Art1 ${CURRENT_DIR} | tail -n 1)
    if [ ! -f ${FILE} ]; then
        CURRENT_DIR="${CURRENT_DIR}/${FILE}"
        zob
    fi
    echo $FILE
    exit
}
zob

Đây là một hàm đệ quy, người nhận được mục sửa đổi gần đây nhất của một thư mục. Nếu mục này là một thư mục, chức năng được gọi đệ quy và tìm kiếm trong thư mục này, v.v.


3

Tôi tìm thấy sau đây ngắn hơn và với đầu ra dễ hiểu hơn:

find . -type f -printf '%TF %TT %p\n' | sort | tail -1

Với độ dài cố định của thời gian định dạng ISO được tiêu chuẩn hóa, sắp xếp từ điển là tốt và chúng tôi không cần -ntùy chọn sắp xếp.

Nếu bạn muốn xóa dấu thời gian một lần nữa, bạn có thể sử dụng:

find . -type f -printf '%TFT%TT %p\n' | sort | tail -1 | cut -f2- -d' '

2

Nếu chạy stattrên từng tệp riêng lẻ là để làm chậm, bạn có thể sử dụng xargsđể tăng tốc mọi thứ lên một chút:

find . -type f -print0 | xargs -0 stat -f "%m %N" | sort -n | tail -1 | cut -f2- -d" " 

2

Điều này đệ quy thay đổi thời gian sửa đổi của tất cả các thư mục trong thư mục hiện tại thành tệp mới nhất trong mỗi thư mục:

for dir in */; do find $dir -type f -printf '%T@ "%p"\n' | sort -n | tail -1 | cut -f2- -d" " | xargs -I {} touch -r {} $dir; done

1
Nó bị hỏng nặng nếu bất kỳ thư mục nào chứa khoảng trắng - cần đặt IFS và sử dụng dấu ngoặc kép: IFS = $ '\ n'; cho thư mục trong $ (find ./ -type d); làm tiếng vang "$ dir"; tìm "$ dir" -type f -printf '% T @ "% p" \ n' | sắp xếp -n | đuôi -1 | cắt -f2- -d "" | xargs -I {} touch -r {} "$ dir"; làm xong;
Andy Lee Robinson

2

Cli đơn giản này cũng sẽ hoạt động:

ls -1t | head -1

Bạn có thể thay đổi -1 thành số lượng tệp bạn muốn liệt kê


10
Không, nó sẽ không, vì nó không được đệ quy.
arataj

1

Tôi thấy lệnh trên hữu ích, nhưng đối với trường hợp của tôi, tôi cần xem ngày và giờ của tệp cũng như tôi gặp vấn đề với một số tệp có khoảng trắng trong tên. Đây là giải pháp làm việc của tôi.

find . -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | sed 's/.*/"&"/' | xargs ls -l

1

Lệnh sau hoạt động trên Solaris:

find . -name "*zip" -type f | xargs ls -ltr | tail -1 

1

Bỏ qua các tập tin ẩn - với dấu thời gian đẹp và nhanh

$ find . -type f -not -path '*/\.*' -printf '%TY.%Tm.%Td %THh%TM %Ta %p\n' |sort -nr |head -n 10

Kết quả

Xử lý không gian trong tên tập tin tốt - không nên sử dụng chúng!

2017.01.25 18h23 Wed ./indenting/Shifting blocks visually.mht
2016.12.11 12h33 Sun ./tabs/Converting tabs to spaces.mht
2016.12.02 01h46 Fri ./advocacy/2016.Vim or Emacs - Which text editor do you prefer?.mht
2016.11.09 17h05 Wed ./Word count - Vim Tips Wiki.mht

Hơn

Nhiều find galore sau liên kết.


1

Để tìm kiếm các tệp trong / target_directory và tất cả các thư mục con của nó, đã được sửa đổi trong 60 phút qua:

$ find /target_directory -type f -mmin -60

Để tìm các tệp được sửa đổi gần đây nhất, hãy sắp xếp theo thứ tự ngược lại của thời gian cập nhật (nghĩa là các tệp được cập nhật gần đây nhất trước tiên):

$ find /etc -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r


0

Tôi đã viết một gói pypi / github cho câu hỏi này vì tôi cũng cần một giải pháp.

https://github.com/bucknerns/logtail

Tải về:

pip install logtail

Cách sử dụng: đuôi đã thay đổi tập tin

logtail <log dir> [<glob match: default=*.log>]

Cách sử dụng2: Mở tệp thay đổi mới nhất trong trình chỉnh sửa

editlatest <log dir> [<glob match: default=*.log>]
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.