Làm thế nào để tìm đệ quy và liệt kê các tệp sửa đổi mới nhất trong một thư mục có thư mục con và thời gian?


417
  • Hệ điều hành: Linux

  • Kiểu hệ thống tập tin: ext3

  • Giải pháp ưa thích: bash (script / oneliner), ruby, python

Tôi có một số thư mục với một số thư mục con và tập tin trong đó. Tôi cần lập một danh sách tất cả các thư mục này được xây dựng theo cách sao cho mọi thư mục cấp đầu tiên được liệt kê bên cạnh ngày và giờ của tệp được tạo / sửa đổi mới nhất trong đó.

Để làm rõ, nếu tôi chạm vào một tệp hoặc sửa đổi nội dung của nó một vài cấp độ thư mục con xuống, dấu thời gian đó sẽ được hiển thị bên cạnh tên thư mục cấp đầu tiên. Nói rằng tôi có một thư mục có cấu trúc như thế này:

./alfa/beta/gamma/example.txt

và tôi sửa đổi nội dung của tệp example.txt, tôi cần thời gian đó được hiển thị bên cạnh thư mục cấp đầu tiên alfaở dạng người có thể đọc được, không phải epoch. Tôi đã thử một số thứ sử dụng tìm kiếm, xargs, sortvà thích nhưng tôi không thể nhận được xung quanh vấn đề rằng dấu thời gian hệ thống tập tin của 'alfa' không thay đổi khi tôi có thể tạo / chỉnh sửa các file một vài cấp độ xuống.


Nếu bạn có thể chịu khó xây dựng nó, github.com/shadkam/recent most có thể được sử dụng.
dùng3392225

4
Đáng kinh ngạc. 16 câu trả lời, và hầu hết / tất cả thậm chí không cố gắng làm những gì OP chỉ định ...
hmijail thương tiếc những người từ chức

Thay vì các giải pháp như chuyển đổi -R, tôi chỉ thấy số lượng lớn ở đây.
neverMind9

Nên là một tính năng bản địa.
neverMind9

Câu trả lời:


486

Hãy thử cái này:

#!/bin/bash
find $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

Thực hiện nó với đường dẫn đến thư mục nơi nó sẽ bắt đầu quét đệ quy (nó hỗ trợ tên tệp có dấu cách).

Nếu có nhiều tệp, có thể mất một lúc trước khi trả về bất cứ thứ gì. Hiệu suất có thể được cải thiện nếu chúng ta sử dụng xargsthay thế:

#!/bin/bash
find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

đó là một chút nhanh hơn.


132
"Phương thức nhanh" của bạn cũng sẽ có thể sử dụng print0 để hỗ trợ các khoảng trắng và thậm chí các nguồn cấp dữ liệu trong tên tệp. Đây là những gì tôi sử dụng: find $1 -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head Điều này vẫn giúp tôi nhanh chóng.
Dan

20
Trên Mac OS X, không phải stat của GNU nên lệnh bị lỗi. Bạn phải brew install coreutilsvà sử dụng gstatthay vìstat
CharlesB

36
Bạn không cần phải chạy statfind PATH -type f -printf "%T@ %p\n"| sort -nrcông việc. Đó cũng là một chút nhanh hơn theo cách đó.
nr

4
bằng cách nào đó chúng ta có thể biến nhận xét của @ user37078 thành câu trả lời thực tế hoặc chỉnh sửa câu trả lời ban đầu không? nó có vẻ là "đúng cách" [tm] để làm điều đó.
mnagel

6
Trên Mac OS X, không cần cài đặt gstat hoặc bất cứ điều gì khác, bạn có thể làm:find PATH -type f -exec stat -f "%m %N" "{}" \; | sort -nr | head
cobbzilla

198

Để tìm tất cả các tệp mà trạng thái tệp đã được thay đổi lần cuối N phút trước:

find -cmin -N

ví dụ:

find -cmin -5


4
+1 Cảm ơn, rất hữu ích. Hoạt động trên Windows bằng GnuWin32 find.
Sabuncu

rất ngắn gọn rất đẹp!
Randy L

nó nhanh hơn các giải pháp khác phức tạp hơn
david.perez

20
Thực sự tốt, bạn cũng có thể sử dụng 'find -ctime -50' trong 50 ngày thay đổi cuối cùng.
Gorkem

1
Để loại trừ sự lộn xộn, hãy sử dụngsudo find -cmin -1 2>&1 |grep -v /proc/
Cees Timmerman

39

GNU Find (xem man find) có một -printftham số để loại bỏ các tệp EPOC mtime và tên đường dẫn tương đối.

redhat> find . -type f -printf '%T@ %P\n' | sort -n | awk '{print $2}'

3
Cảm ơn! Đây là câu trả lời duy nhất đủ nhanh để tìm kiếm thông qua cấu trúc thư mục rất rộng của tôi trong một thời gian hợp lý. Tôi chuyển đầu ra qua tailđể ngăn hàng ngàn dòng được in ở đầu ra.
sffc

8
Một nhận xét khác: awk '{print $2}'phần dường như gây ra vấn đề khi có tên tệp có khoảng trắng. Đây là một giải pháp sử dụng sedthay thế, và nó cũng in thời gian bên cạnh đường dẫn:find . -type f -printf '%T@ %Tc %P\n' | sort -n | tail | sed -r 's/^.{22}//'
sffc

3
Tôi nghĩ nó nên được sắp xếp
Bojan Dević

2
Biến thể -printf nhanh hơn nhiều so với việc gọi quy trình 'stat' mỗi lần - nó cắt giảm hàng giờ công việc sao lưu của tôi. Cảm ơn đã làm cho tôi nhận thức được điều này. Tôi đã tránh điều awk / sed vì tôi chỉ quan tâm đến bản cập nhật cuối cùng trong cây - vì vậy X = $ (find / path -type f -printf '% T% p \ n' | grep -v Something-I- don-tcare-about | sort -nr | head -n 1) và một tiếng vang $ {X # * ""} hoạt động tốt với tôi (đưa tôi đến không gian đầu tiên)
David Goodwin

2
Tất cả sẽ không hoạt động nếu tên tệp trên nhiều dòng. Sử dụng touch "lala<Enter>b"để tạo tập tin như vậy. Tôi nghĩ thiết kế tiện ích unix có lỗ hổng lớn về tên tệp.
Trái cây

35

Tôi rút ngắn câu trả lời tuyệt vời của quầng sáng cho lớp lót này

stat --printf="%y %n\n" $(ls -tr $(find * -type f))

Đã cập nhật : Nếu có khoảng trắng trong tên tệp, bạn có thể sử dụng sửa đổi này

OFS="$IFS";IFS=$'\n';stat --printf="%y %n\n" $(ls -tr $(find . -type f));IFS="$OFS";

Làm thế nào về điều này: IFS = $ '\ n'; stat --printf = "% y% n \ n" $ (ls -tr $ (tìm. -type f))
slashdottir

3
Điều này sẽ không hoạt động nếu bạn có một số lượng rất lớn các tập tin. các câu trả lời sử dụng xargs giải quyết giới hạn đó.
carl verbiest

@carlverbiest thực sự là một số lượng lớn các tệp sẽ phá vỡ giải pháp của slashdottir. Ngay cả các giải pháp dựa trên xargs cũng sẽ chậm. Giải pháp của user2570243 là tốt nhất cho các hệ thống tập tin lớn.
Stéphane Gourichon

IFS=$'\n'không an toàn trong mọi trường hợp khi xử lý tên tệp: Dòng mới là ký tự hợp lệ trong tên tệp trên UNIX. Chỉ có nhân vật NUL được đảm bảo không có mặt trong một đường dẫn.
Charles Duffy

17

Thử cái này

#!/bin/bash
stat --format %y $(ls -t $(find alfa/ -type f) | head -n 1)

Nó sử dụng findđể thu thập tất cả các tệp từ thư mục, lsđể liệt kê chúng được sắp xếp theo ngày sửa đổi, headđể chọn tệp đầu tiên và cuối cùngstat để hiển thị thời gian ở định dạng đẹp.

Tại thời điểm này, nó không an toàn cho các tệp có khoảng trắng hoặc ký tự đặc biệt khác trong tên của chúng. Viết một lời khen nếu nó chưa đáp ứng nhu cầu của bạn.


1
hào quang: Tôi thích câu trả lời của bạn, nó hoạt động tốt và in ra các tập tin chính xác. Tôi không giúp tôi tuy nhiên vì có quá nhiều cấp dưới trong trường hợp của tôi. Vì vậy, tôi nhận được "Danh sách đối số quá dài" cho ls ... và xargs cũng không giúp được gì trong trường hợp này. Tôi sẽ thử thứ khác.
fredrik

Trong trường hợp đó, nó phức tạp hơn một chút và sẽ cần một số chương trình thực sự. Tôi sẽ hack một số Perl.
Daniel Böhmer

1
Tôi đã giải quyết điều này bằng cách sử dụng PHP thay thế. Một hàm đệ quy đi xuống qua cây hệ thống tệp và lưu trữ thời gian của tệp được sửa đổi gần đây nhất.
fredrik

11

Lệnh này hoạt động trên Mac OS X:

find "$1" -type f -print0 | xargs -0 stat --format '%Y :%y %n' | sort -nr | cut -d: -f2- | head

Trên Linux, như người đăng ban đầu đã hỏi, hãy sử dụng statthay vìgstat .

Câu trả lời này, tất nhiên, là giải pháp nổi bật của user37078 , được quảng bá từ bình luận đến câu trả lời đầy đủ. Tôi đã trộn lẫn trong cái nhìn sâu sắc của CharlesB để sử dụng gstattrên Mac OS X. Tôi đã nhận được coreutils từ MacPorts chứ không phải homebrew .

Và đây là cách tôi đóng gói nó thành một lệnh đơn giản ~/bin/ls-recent.shđể sử dụng lại:

#!/bin/bash
# ls-recent: list files in a dir tree, most recently modified first
#
# Usage: ls-recent path [-10 | more]
# 
# Where "path" is a path to target directory, "-10" is any arg to pass
# to "head" to limit the number of entries, and "more" is a special arg
# in place of "-10" which calls the pager "more" instead of "head".
if [ "more" = "$2" ]; then
   H=more; N=''
else
   H=head; N=$2
fi

find "$1" -type f -print0 |xargs -0 gstat --format '%Y :%y %n' \
    |sort -nr |cut -d: -f2- |$H $N

2
Trên OS X yosemite; Tôi gặp lỗi: find: ftsopen: Không có tệp hoặc thư mục như vậy
Reece

Hấp dẫn. Lệnh nào bạn đã gõ (có tham số)? Và tên của các tập tin trong thư mục đó là gì? Và nếu bạn tạo phiên bản của riêng mình ~/bin/ls-recent.sh, bạn đã kiểm tra cẩn thận kịch bản chưa?
Jim DeLaHunt

10
dành cho những người không muốn cài đặt bất cứ thứ gì trên Mac OS X:find . -exec stat -f '%m%t%Sm %N' {} + | sort -n | cut -f2-
Jake

5

Cả hai giải pháp perl và Python trong bài đăng này đều giúp tôi giải quyết vấn đề này trên Mac OS X: /unix/9247/how-to-list-files-sortic-by-modification-date-recursively -no-stat-lệnh-avail .

Trích dẫn từ bài viết:

Perl:

find . -type f -print |
perl -l -ne '
    $_{$_} = -M;  # store file age (mtime - now)
    END {
        $,="\n";
        print sort {$_{$b} <=> $_{$a}} keys %_;  # print by decreasing age
    }'

Con trăn

find . -type f -print |
python -c 'import os, sys; times = {}
for f in sys.stdin.readlines(): f = f[0:-1]; times[f] = os.stat(f).st_mtime
for f in sorted(times.iterkeys(), key=lambda f:times[f]): print f'

5

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

Xử lý không gian trong tên tệp tốt - không phải là bạn nên sử dụng chúng!

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

2017.01.28 07h00 Sat ./recent
2017.01.21 10h49 Sat ./hgb
2017.01.16 07h44 Mon ./swx
2017.01.10 18h24 Tue ./update-stations
2017.01.09 10h38 Mon ./stations.json

Nhiều findgalore có thể được tìm thấy bằng cách theo liên kết.


3

Tôi đang hiển thị điều này cho thời gian truy cập mới nhất, bạn có thể dễ dàng sửa đổi điều này để thực hiện thời gian mod mới nhất.

Có hai cách để làm điều này:


1) Nếu bạn muốn tránh sắp xếp toàn cầu có thể tốn kém nếu bạn có hàng chục triệu tệp, thì bạn có thể thực hiện: (đặt mình vào thư mục gốc của thư mục nơi bạn muốn tìm kiếm bắt đầu)

linux> touch -d @0 /tmp/a;
linux> find . -type f -exec tcsh -f -c test `stat --printf="%X" {}` -gt  `stat --printf="%X" /tmp/a`  ; -exec tcsh -f -c touch -a -r {} /tmp/a ; -print 

Phương pháp trên in tên tệp với thời gian truy cập mới hơn dần dần và tệp cuối cùng mà nó in là tệp có thời gian truy cập mới nhất. Rõ ràng bạn có thể có được thời gian truy cập mới nhất bằng cách sử dụng "đuôi -1".


2) Bạn có thể tìm thấy in đệ quy tên, thời gian truy cập của tất cả các tệp trong thư mục con của bạn và sau đó sắp xếp dựa trên thời gian truy cập và đuôi là mục lớn nhất:

linux> \find . -type f -exec stat --printf="%X  %n\n" {} \; | \sort -n | tail -1

Và bạn có nó rồi đấy...


3

Tôi có bí danh này trong .profile của tôi mà tôi sử dụng khá thường xuyên

$ alias | grep xlogs
xlogs='sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R'

Vì vậy, nó thực hiện những gì bạn đang tìm kiếm (ngoại trừ nó không thay đổi nhiều cấp độ ngày / giờ) - tìm kiếm các tệp mới nhất (* .log và * .trc trong trường hợp này); Ngoài ra, nó chỉ tìm thấy các tệp được sửa đổi vào ngày hôm trước, sau đó sắp xếp theo thời gian và đầu ra của ống thông qua ít hơn:

sudo find . \( -name "*.log" -o -name "*.trc" \) -mtime -1 | sudo xargs ls -ltr --color | less -R

ps. Lưu ý rằng tôi không có root trên một số máy chủ, nhưng luôn có sudo, vì vậy bạn có thể không cần phần đó.


Làm thế nào là "chính xác những gì bạn đang tìm kiếm"? OP đã viết một lời giải thích tốt về những gì anh ta muốn, và điều này hoàn toàn bỏ qua nó.
hmijail thương tiếc người từ chức

cảm ơn đã chỉ ra điều đó bạn đã đúng - phương pháp này không đi nhiều cấp độ để thay đổi ngày / giờ, nó chỉ hiển thị ngày / giờ của các tệp trong thư mục. chỉnh sửa câu trả lời của tôi.
Tagar

1

Bạn có thể đưa ra lệnh printf tìm thử

Thời gian truy cập cuối cùng của% Ak File theo định dạng được chỉ định bởi k, đó là @' or a directive for the C chức năng strftime '. Các giá trị có thể cho k được liệt kê dưới đây; một số trong số chúng có thể không có sẵn trên tất cả các hệ thống, do sự khác biệt về 'strftime' giữa các hệ thống.


1

Chức năng bash nhanh:

# findLatestModifiedFiles(directory, [max=10, [format="%Td %Tb %TY, %TT"]])
function findLatestModifiedFiles() {
    local d="${1:-.}"
    local m="${2:-10}"
    local f="${3:-%Td %Tb %TY, %TT}"

    find "$d" -type f -printf "%T@ :$f %p\n" | sort -nr | cut -d: -f2- | head -n"$m"
}

Tìm tập tin sửa đổi mới nhất trong một thư mục:

findLatestModifiedFiles "/home/jason/" 1

Bạn cũng có thể chỉ định định dạng ngày / giờ của riêng mình làm đối số thứ ba.


1

Sau đây trả về cho bạn một chuỗi dấu thời gian và tên của tệp có dấu thời gian gần đây nhất:

find $Directory -type f -printf "%TY-%Tm-%Td-%TH-%TM-%TS %p\n" | sed -r 's/([[:digit:]]{2})\.([[:digit:]]{2,})/\1-\2/' |     sort --field-separator='-' -nrk1 -nrk2 -nrk3 -nrk4 -nrk5 -nrk6 -nrk7 | head -n 1

Kết quả là một đầu ra của mẫu: <yy-mm-dd-hh-mm-ss.nanosec> <filename>


1

Đây là một phiên bản hoạt động với tên tệp có thể chứa khoảng trắng, dòng mới, ký tự toàn cầu:

find . -type f -printf "%T@ %p\0" | sort -zk1nr
  • find ... -printf in sửa đổi tệp (giá trị EPOCH) theo sau là khoảng trắng và \0 tên tệp kết thúc.
  • sort -zk1nr đọc dữ liệu kết thúc NUL và sắp xếp ngược lại bằng số

Vì câu hỏi được gắn thẻ với Linux nên tôi giả sử gnu các tiện ích có sẵn.

Bạn có thể đặt ống ở trên với:

xargs -0 printf "%s\n"

để in thời gian sửa đổi và tên tệp được sắp xếp theo thời gian sửa đổi (lần đầu tiên gần đây nhất) được chấm dứt bởi dòng mới.


1

Đây là những gì tôi đang sử dụng (rất hiệu quả):

function find_last () { find "${1:-.}" -type f -printf '%TY-%Tm-%Td %TH:%TM %P\n' 2>/dev/null | sort | tail -n "${2:-10}" }

PROS:

  • nó chỉ sinh ra 3 quá trình

SỬ DỤNG:

find_last [dir [number]]

Ở đâu:

  • dir - một thư mục cần tìm kiếm [thư mục hiện tại]
  • number - số lượng tệp mới nhất để hiển thị [10]

Đầu ra cho find_last /etc 4hình như thế này:

2019-07-09 12:12 cups/printers.conf
2019-07-09 14:20 salt/minion.d/_schedule.conf
2019-07-09 14:31 network/interfaces
2019-07-09 14:41 environment

0

Đối với lsđầu ra đơn giản , sử dụng này. Không có danh sách đối số, vì vậy nó không thể quá dài:

find . | while read FILE;do ls -d -l "$FILE";done

Và tốt đẹp cutchỉ với ngày, giờ và tên:

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5

EDIT : Chỉ cần lưu ý rằng câu trả lời hàng đầu hiện tại sắp xếp theo ngày sửa đổi. Điều đó thật dễ dàng với ví dụ thứ hai ở đây, vì ngày sửa đổi là lần đầu tiên trên mỗi dòng - tát một loại vào cuối:

find . | while read FILE;do ls -d -l "$FILE";done | cut --complement -d ' ' -f 1-5 | sort

0

Điều này có thể được thực hiện với chức năng đệ quy trong bash

Đặt cho F một hàm hiển thị thời gian của tệp phải được sắp xếp theo từ vựng yyyy-mm-dd, v.v., (phụ thuộc os?)

F(){ stat --format %y "$1";}                # Linux
F(){ ls -E "$1"|awk '{print$6" "$7}';}      # SunOS: maybe this could be done easier

R hàm đệ quy chạy qua các thư mục

R(){ local f;for f in "$1"/*;do [ -d "$f" ]&&R $f||F "$f";done;}

Và cuối cùng

for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done
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.