如何递归查找和列出具有子目录和时间的目录中的最新修改文件?

时间:2011-04-06 12:26:18

标签: linux recursion time filesystems

  • 操作系统:Linux

  • 文件系统类型:ext3

  • 首选解决方案:bash(script / oneliner),ruby,python

我有几个目录,里面有几个子目录和文件。我需要列出所有这些目录,这些目录的构造方式使得每个第一级目录都列在其中最新创建/修改文件的日期和时间旁边。

为了澄清,如果我触摸文件或将其内容修改为几个子目录级别,那么该时间戳应该显示在第一级目录名称旁边。假设我有一个像这样的结构目录:

./alfa/beta/gamma/example.txt

我修改了文件example.txt的内容,我需要以人类可读形式显示在第一级目录alfa旁边的时间,而不是epoch。我已经尝试了一些使用find,xargssort之类的东西,但是当我创建/修改文件时,我无法解决'alfa'的文件系统时间戳没有改变的问题几级下来。

21 个答案:

答案 0 :(得分:430)

试试这个:

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

使用它应该以递归方式开始扫描的目录的路径执行它(它支持带空格的文件名)。

如果文件很多,可能需要一段时间才会返回任何内容。如果我们使用xargs代替,则可以提高效果:

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

这有点快。

答案 1 :(得分:169)

要查找文件状态上次更改的所有文件 N 分钟前:

find -cmin -N

例如:

find -cmin -5

答案 2 :(得分:37)

GNU Find(请参阅man find)有一个-printf参数,用于显示文件EPOCh时间和相对路径名。

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

答案 3 :(得分:33)

我缩短了光环对这个单线的真棒答案

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

已更新:如果文件名中有空格,则可以使用此修改

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

答案 4 :(得分:13)

试试这个

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

使用find收集目录中的所有文件,ls列出按修改日期排序的文件,head选择第一个文件,最后stat显示时间很好。

目前,名称中包含空格或其他特殊字符的文件不安全。如果它还不能满足您的需求,请写一个表扬。

答案 5 :(得分:10)

此命令适用于Mac OS X:

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

在Linux上,正如原始海报所问,使用stat代替gstat

这个答案当然是user37078出色的解决方案,从评论到完整答案。我在CharlesB的洞察力中混合了在Mac OS X上使用gstat。顺便说一句,我从MacPorts而不是homebrew获得 coreutils

以下是我将其打包成一个简单的命令~/bin/ls-recent.sh以供重用:

#!/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

答案 6 :(得分:5)

这篇文章中的perl和Python解决方案都帮助我在Mac OS X上解决了这个问题:https://unix.stackexchange.com/questions/9247/how-to-list-files-sorted-by-modification-date-recursively-no-stat-command-avail

从帖子中引用:

的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
    }'

的Python:

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'

答案 7 :(得分:3)

我正在显示最新的访问时间,您可以轻松修改它以执行最新的模拟时间。

有两种方法可以做到这一点:


1)如果你想避免全局排序,如果你有数千万个文件,这可能会很昂贵,那么你可以这样做:(将你自己置于你希望搜索开始的目录的根目录中)

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 

上述方法打印文件名的访问时间越来越长,打印的最后一个文件是具有最新访问时间的文件。显然,您可以使用“tail -1”获取最新的访问时间。


2)您可以找到递归打印名称,访问子目录中所有文件的时间,然后根据访问时间和尾部排序最大的条目:

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

你有它......

答案 8 :(得分:3)

我在我的.profile中有这个别名,我经常使用

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

所以它可以满足您的需求(除了它不会遍历更改多个级别的日期/时间) - 查找最新文件(在这种情况下为* .log和* .trc文件);它也只查找在最后一天修改的文件,然后按时间排序并通过less输出管道输出:

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

PS。注意我在某些服务器上没有root,但总是有sudo,所以你可能不需要那个部分。

答案 9 :(得分:2)

忽略隐藏文件 - 包含好的&amp;快速时间戳

很好地处理文件名中的空格 - 而不是你应该使用它们!

$ 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
可以通过链接找到

More find galore

答案 10 :(得分:1)

@anubhava's answer 很棒,但不幸的是不能在 BSD 工具上工作——即它不能与 find that comes installed by default on macOS 一起工作,因为 BSD find 没有 {{1 }} 运算符。

所以这里有一个适用于 macOS + BSD 的变体(在我的 Catalina Mac 上测试过),它结合了 BSD -printfxargsstat

find

当我在这里时,这是我喜欢使用的 BSD 命令序列,它将时间戳放在 ISO-8601 format

$ find . -type f -print0 \
      | xargs -0 -n1 -I{} stat -f '%Fm %N' "{}" \
      | sort -rn 

(请注意,与@anubhava 不同,我的两个答案都将文件名从 $ find . -type f -print0 \ | xargs -0 -n1 -I{} \ stat -f '%Sm %N' -t '%Y-%m-%d %H:%M:%S' "{}" \ | sort -rn 传递到 find 作为单个参数而不是 xargs 终止列表,这会改变输出的内容最后)

这是 GNU 版本(即@anubhava 的答案,但采用 iso-8601 格式):

\0

相关问题:find lacks the option -printf, now what?

答案 11 :(得分:1)

快速重击功能:

# 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"
}

在目录中找到最新修改的文​​件:

findLatestModifiedFiles "/home/jason/" 1

您还可以指定自己的日期/时间格式作为第三个参数。

答案 12 :(得分:1)

以下内容将返回时间戳的字符串以及具有最新时间戳的文件名:

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

导致表单的输出: <yy-mm-dd-hh-mm-ss.nanosec> <filename>

答案 13 :(得分:1)

这是一个适用于文件名的版本,其中可能包含空格,换行符,整数字符:

find . -type f -printf "%T@ %p\0" | sort -zk1nr
  • find ... -printf打印文件修改(EPOCH值),后跟空格和\0终止的文件名。
  • sort -zk1nr读取NUL终止的数据并按数字顺序排序

由于问题是用Linux标记的,所以我假设gnu utils可用。

您可以通过以下方式管道:

xargs -0 printf "%s\n"

打印修改时间和按修改时间排序的文件名(最近的第一个)由换行符终止。

答案 14 :(得分:1)

这实际上应该执行OP所指定的操作:

Bash中的单线:

$ for first_level in `find . -maxdepth 1 -type d`; do find $first_level -printf "%TY-%Tm-%Td %TH:%TM:%TS $first_level\n" | sort -n | tail -n1 ; done

给出如下输出:

2020-09-12 10:50:43.9881728000 .
2020-08-23 14:47:55.3828912000 ./.cache
2018-10-18 10:48:57.5483235000 ./.config
2019-09-20 16:46:38.0803415000 ./.emacs.d
2020-08-23 14:48:19.6171696000 ./.local
2020-08-23 14:24:17.9773605000 ./.nano

这将列出每个第一级目录以及这些文件夹中最新文件的可读时间戳,即使该文件位于子文件夹中,也应按照

的要求进行操作

“我需要列出所有这些目录的列表 这样,每个第一级目录都会在日期旁边列出 以及其中最近创建/修改的文件的时间。”

答案 15 :(得分:0)

对于那些面对的人

stat: unrecognized option: format

Heppo's answerfind $1 -type f -exec stat --format '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head)开始执行行时

请尝试使用-c键替换--format,最后的呼叫将是:

find $1 -type f -exec stat -c '%Y :%y %n' "{}" \; | sort -nr | cut -d: -f2- | head

这在某些Docker容器中对我有用,其中stat无法使用--format选项。

答案 16 :(得分:0)

在 mac 上我用这个

find . -type f -exec stat -f "%m %N" "{}" \; | sort -nr | perl -n -e '@a = split / /;print `ls -l $a[1]`' | vim -

如果你想过滤一些文件,你可以使用带有正则表达式的grep,即

find . -type f -exec stat -f "%m %N" "{}" \; | sort -nr | grep -v -E \.class$ | perl -n -e '@a = split / /;print `ls -l $a[1]`' | vim -

答案 17 :(得分:0)

这就是我正在使用的(非常有效):

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

优点:

  • 它仅产生3个进程

用法:

find_last [dir [number]]

其中:

  • dir-要搜索的目录[当前目录]
  • number-要显示的最新文件数[10]

find_last /etc 4的输出如下:

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

答案 18 :(得分:0)

这可以通过bash中的递归函数来完成

设F显示必须按字典顺序排序yyyy-mm-dd等文件的时间,(os依赖?)

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

R遍历目录的递归函数

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

最后

for f in *;do [ -d "$f" ]&&echo `R "$f"|sort|tail -1`" $f";done

答案 19 :(得分:0)

对于普通ls输出,请使用此选项。没有参数列表,所以它不会太长:

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

仅针对日期,时间和名称cut进行了改进:

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

编辑:注意到当前的最高答案按修改日期排序。这就像第二个例子一样容易,因为修改日期是每行的第一个 - 在一端打一个排序:

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

答案 20 :(得分:0)

你可以给printf命令找个试试

  

%Ak文件的最后访问时间   由k指定的格式,                        这是@' or a directive for the C strftime'                        功能。列出了k的可能值   下面;                        其中一些可能根本不可用   系统,到期                        系统间“strftime”的差异。